mercredi 26 février 2020

Template argument substitution fails and implicit conversion is not done

#include <type_traits>

template<bool Const>
struct view_tpl {
    using value_type = std::conditional_t<Const, const int, int>;
    value_type* ptr;

    view_tpl() = default;
    view_tpl(const view_tpl<false>& other) : ptr(other.ptr) { }
};

using view = view_tpl<false>;
using const_view = view_tpl<true>;

void read(const const_view& vw) { }

int main() {
    view vw;
    read(vw);
}

This code defines a const and a non-const view type, both as aliases to a view_tpl<Const> template. It should be such that view is implicitly convertible to const_view, but not the other way around.

It Const is true, the defined copy-constructor enables this, and the compiler generates an additional default copy-constructor. If Const is false the defined copy-constructor replaces the default copy-constructor.

This implicit conversion should happen when f(vw) is called.

It works correctly in the above code.


But if I add an argument to the templates (int N), and turn f and the two type aliasses into templates, it no longer works:

#include <type_traits>

template<int N, bool Const>
struct view_tpl {
    using value_type = std::conditional_t<Const, const int, int>;
    value_type* ptr;

    view_tpl() = default;
    view_tpl(const view_tpl<N, false>& other) : ptr(other.ptr) { }
};

template<int N> using view = view_tpl<N, false>;
template<int N> using const_view = view_tpl<N, true>;

template<int N>
void read(const const_view<N>& vw) { }

int main() {
    view<0> vw;
    read(vw);
}

Instead of doing the conversion of view_tpl<0, true> to view_tpl<0, false>, the compiler only tries a direct template substitution and fails:

main.cpp: In function 'int main()':
main.cpp:20:12: error: no matching function for call to 'read(view<0>&)'
   20 |     read(vw);
      |            ^
main.cpp:16:6: note: candidate: 'template<int N> void read(const_view<N>&)'
   16 | void read(const const_view<N>& vw) { }
      |      ^~~~
main.cpp:16:6: note:   template argument deduction/substitution failed:
main.cpp:20:12: note:   template argument 'false' does not match 'true'
   20 |     read(vw);
      |            ^

Is there a way to make this work without changing too much of the code? (The real code is more complex than this example)

Aucun commentaire:

Enregistrer un commentaire