我对这个问题得到了完美答案: Specializing class with SFINAE
为了完整性,我再次在此插入正确的解决方案:
class AA { public: using TRAIT = int; };
class BB { public: using TRAIT = float; };
template < typename T, typename UNUSED = void> class X;
template < typename T >
class X<T, typename std::enable_if< std::is_same< int, typename T::TRAIT>::value, void >::type>
{
public:
X() { std::cout << "First" << std::endl; }
};
template < typename T >
class X<T, typename std::enable_if< !std::is_same< int, typename T::TRAIT>::value, void >::type>
{
public:
X() { std::cout << "Second" << std::endl; }
};
int main()
{
X<AA> a;
X<BB> b;
}
但是如果我必须使用参数包进一步使用,我认为没有机会写下这些东西:
template < typename T, typename ...S, typename UNUSED = void> class X;
错误:参数包'S'必须位于模板参数列表的末尾
定义的顺序与
不同template < typename T, typename UNUSED = void, typename ...S> class X;
如果第一个附加类型正在使用,会出现问题。
好的,我所描述的是一种我实际上找不到的技术解决方案。也许有一个不同的。我的根本问题是什么:我需要2个不同的构造函数来调用不同的基类构造函数。但是因为两个构造函数都有相同的参数集,所以我认为没有机会专门构造构造函数。
如果specialize构造函数可以工作,它可以是这样的:
template < typename T>
class Y
{
public:
template <typename U = T, typename V= typename std::enable_if< std::is_same< int, typename U::TRAIT>::value, int >::type>
Y( const V* =nullptr) { std::cout << "First" << std::endl; }
template <typename U = T, typename V= typename std::enable_if< !std::is_same< int, typename U::TRAIT>::value, float >::type>
Y( const V* =nullptr) { std::cout << "Second" << std::endl; }
};
错误:'模板模板Y :: Y(const V *)'无法重载
但正如已经提到的......我不知道是否可以做到。
为了显示潜在的问题,我将给出以下示例,该示例显示了依赖于基类中定义的特征的基类构造函数的不同用法。
template <typename T, typename ... S>: public T
class Z
{
public:
// should work if T defines a trait
Z( typename T::SomeType t): T( t ) {}
// should be used if T defines another trait
Z( typename T::SomeType t): T( ) {}
};
答案 0 :(得分:2)
而不是
template < typename T, typename ...S, typename UNUSED = void> class X;
你可以添加一个图层:
template <typename T, typename Dummy = void, typename ... Ts> class X_impl {};
然后
template <typename T, typename ...Ts>
using X = X_impl<T, void, Ts...>;
对于SFINAE,由于默认模板参数不是签名的一部分,
template <typename U = T,
typename V = std::enable_if_t<std::is_same<int, typename U::TRAIT>::value, int>>
Y(const V* = nullptr) { std::cout << "First" << std::endl; }
template <typename U = T,
typename V = std::enable_if_t<!std::is_same<int,
typename U::TRAIT>::value, float>>
Y(const V* = nullptr) { std::cout << "Second" << std::endl; }
应该重写,例如:
template <typename U = T,
std::enable_if_t<std::is_same<int, typename U::TRAIT>::value>* = nullptr>
Y() { std::cout << "First" << std::endl; }
template <typename U = T,
std::enable_if_t<!std::is_same<int, typename U::TRAIT>::value>* = nullptr>
Y() { std::cout << "Second" << std::endl; }
答案 1 :(得分:0)
template<class...>struct types_tag{using type=types_tag;};
template<class...Ts>constexpr types_tag<Ts...> types{};
这些帮助程序允许您作为一个包,一个参数传递许多类型。
现在您的类型X
可能如下所示:
template<class T, class types, class=void>
class X;
template<class T, class...Ts>>
class X<T, types_tag<Ts...>, std::enable_if_t<true>> {
};
X
的用户传入X<T, types_tag<int, double, char>
。
您可以编写如下的适配器:
template<class T, class...Ts>
using X_t = X<T, types_tag<Ts...>>;
我们使using
别名的名称更好,而不是实现struct
。
作为一种类型传递的类型捆绑可以使一大堆元编程变得简单。你可以传递多个包;并且您可以将types_tag
by-value作为参数传递给函数,以便轻松扣除该包的内容。