我试图一次性使用多种类型的结构模板 SFINAE。我知道类似下面的东西:
#include <iostream>
template <typename T, typename Enable = void>
struct S {
void operator()() {
std::cout << "Instantiated generic case" << std::endl;
}
};
template<typename T>
using enabled_type = typename std::enable_if<
std::is_same<T, int>::value ||
std::is_same<T, float>::value
>::type;
template <typename T>
struct S<T, enabled_type<T>> {
void operator()() {
std::cout << "Instantiated int/float case" << std::endl;
}
};
int main() {
S<float>()();
return 0;
}
我的问题是我无法修改S
的主要模板
struct添加typename Enable = void
,因为它只是外部标题的一部分
图书馆。所以主模板必须如下所示:
template <typename T>
struct S {
void operator()() {
std::cout << "Instantiated generic case" << std::endl;
}
};
有没有办法让我仍然可以使用SFINAE来专门化这个模板?
编辑请注意,S
结构由外部库中的代码使用,因此我必须实际专门化S
并且不能将其子类化。
此外,我正在处理的真实代码要复杂得多,并且从SFINAE中获益远远超过这个简单的例子(我有多个模板参数需要专门针对多种类型的所有组合)。
答案 0 :(得分:2)
你确定简单的旧专业化还不够吗?
struct S_int_or_float {
void operator()() {
std::cout << "Instantiated int/float case" << std::endl;
}
};
template<> struct S<int>: S_int_or_float {};
template<> struct S<float>: S_int_or_float {};
修改强> 你说你必须提供参数的组合...所以至少有两个参数...让我们看看我们能做些什么:
struct ParentS { /* some implementation */ };
template <class First, class Second>
struct S<First, Second, enable_if_t<trait_for_first_and_second<First, Second>::value, first_accepted_type_of_third_parameter> >: ParentS { };
template <class First, class Second>
struct S<First, Second, enable_if_t<trait_for_first_and_second<First, Second>::value, second_accepted_type_of_third_parameter> >: ParentS { };
// ...
它不像SFINAE那样会有额外的参数,但仍然没有指数......
答案 1 :(得分:2)
我有个坏消息:你想要的是不可能的。如果主模板没有额外的模板参数,默认为void
以进行enable_if
,那么就没有办法在最普遍的意义上做到这一点。你最接近的是专门为模板类本身构造结构,换句话说:
template <class T>
struct foo {};
template <class T>
struct S<foo<T>> {};
这会奏效。但显然,如果匹配特征,这不会产生与专业化相同的灵活性。
您的问题实际上完全等同于尝试为满足特征的任何类型专门化std::hash
的问题。与您的问题一样,主类模板定义不能像在库代码中那样更改,并且库代码实际上在某些情况下会自动在内部使用hash
的特化,因此无法真正定义新的模板类。
您可以在此处看到类似的问题:Specializing std::hash to derived classes。从类继承是一个很好的例子,可以表示为特征,但不是模板化的类。一些知识渊博的C ++人都关注这个问题,没有人提供比OP编写宏来自动消除专业化的解决方案更好的答案。不幸的是,我认为这对你来说也是最好的解决方案。
回想起来,hash
或许应该使用第二个模板参数声明,默认为void以支持此用例,而在其他情况下开销最小。我本来可以发誓我甚至在某个地方看过关于这个问题的讨论,但是我无法追踪它。对于您的库代码,您可能会尝试提交问题以让他们更改它。它似乎不是一个突破性的变化,即:
template <class T, class = void>
struct S {};
template <>
struct S<double> {};
似乎有效。