Наследование и явные конструкторы?
Рассмотрим следующий код:
template<typename T> class Base
{
Base();
Base(const Base<T>& rhs);
template<typename T0> explicit Base(const Base<T0>& rhs);
template<typename T0, class = typename std::enable_if<std::is_fundamental<T0>::value>::type> Base(const T0& rhs);
explicit Base(const std::string& rhs);
};
template<typename T> class Derived : Base<T>
{
Derived();
Derived(const Derived<T>& rhs);
template<class T0> Derived(const T0& rhs) : Base(rhs);
// Is there a way to "inherit" the explicit property ?
// Derived(double) will call an implicit constructor of Base
// Derived(std::string) will call an explicit constructor of Base
};
Есть ли способ изменить этот код таким образом, чтобы Derived
будет иметь все конструкторы Base
с такими же явными / неявными свойствами?
2 ответа
C++11 предлагает это как особенность. Тем не менее, даже GCC на самом деле не реализует его.
Когда это на самом деле реализовано, это будет выглядеть так:
template<typename T> class Derived : Base<T>
{
using Base<T>::Base;
};
При этом, это может не помочь в вашем случае. Унаследованные конструкторы - это предложение типа "все или ничего". Вы получаете все конструкторы базового класса, используя именно их параметры. Кроме того, если вы определяете конструктор с той же сигнатурой, что и унаследованную, вы получаете ошибку компиляции.
Чтобы обнаружить неявную / явную конструктивность для SFINAE:
template<class T0, typename std::enable_if<
std::is_convertible<const T0 &, Base<T>>::value, int>::type = 0>
Derived(const T0& rhs) : Base<T>(rhs) { }
template<class T0, typename std::enable_if<
std::is_constructible<Base<T>, const T0 &>::value
&& !std::is_convertible<const T0 &, Base<T>>::value, int>::type = 0>
explicit Derived(const T0& rhs) : Base<T>(rhs) { }
Используйте тот факт, что std::is_convertible
проверяет неявную конвертируемость и использование std::is_constructible
дополнительно проверить явную конвертируемость.
Редактировать: исправлено enable_if
параметры шаблона, использующие решение из boost::enable_if не в сигнатуре функции.
Проверки:
Derived<int>{5}; // allowed
[](Derived<int>){}(5); // allowed
Derived<int>{std::string{"hello"}}; // allowed
[](Derived<int>){}(std::string{"hello"}); // not allowed