I have a set of classes roughly defined as follows:
template <typename U>
class Iterable {
// More code
};
class Container : public Iterable<Element> {
// More code
};
class Tuple : public Container {
// More code
};
class List {
public:
template <typename I, typename T>
requires std::is_base_of_v<Iterable<T>,I>
explicit List(const I& i) {
for (const T& e : i) elems_.emplace_back(e,true);
}
// More code
};
Trying to create a List
from Tuple
as
Tuple t1(1,2,3);
List l1(t1);
gives the following complilation message
/home/felix/git/libraries/cpp_script/tests/test_list.cpp:96:15: error: no matching function for call to ‘cs::List::List(cs::Tuple&)’
96 | List l1(t1);
| ^
In file included from /home/felix/git/libraries/cpp_script/tests/test_list.cpp:3:
/home/felix/git/libraries/cpp_script/include/list.hpp:72:10: note: candidate: ‘template<class I, class T> requires is_base_of_v<cs::Iterable<T>, I> cs::List::List(const I&)’
72 | explicit List(const I& i) {
| ^~~~
/home/felix/git/libraries/cpp_script/include/list.hpp:72:10: note: template argument deduction/substitution failed:
/home/felix/git/libraries/cpp_script/tests/test_list.cpp:96:15: note: couldn’t deduce template parameter ‘T’
96 | List l1(t1);
| ^
I don't understand why the substitution fails. I==Tuple
and T==Element
should satisfy the require
clause just fine.
CodePudding user response:
Your example won't work because there is no way to deduce the type of T
.
If you want to constrain I
to inherit from base class Iterable<U>
for some type U
, you might want to do
template <typename U>
class Iterable { };
template<typename T>
concept derived_from_iterable = requires (T& x) {
[]<typename U>(Iterable<U>&){}(x);
};
class List {
public:
template<derived_from_iterable I>
explicit List(const I& i) {
// More code
}
};