Cla*_*diu 3 c++ generics templates sfinae c++11
我有十几个函数,它们有两个参数:泛型和特定类型.例如:
template <class A, class B>
void foo(A& a, B& b)
{
cout << "generic fallback" << endl;
}
template <class A>
void foo(A& a, int &i)
{
cout << "generic int" << endl;
}
template <class A>
void foo(A& a, string& s)
{
cout << "generic str" << endl;
}
Run Code Online (Sandbox Code Playgroud)
我想创建一个重载,只要A
是特定结构的实例[1] 就会调用它.到目前为止我想出的最好的是:
struct mine
{
int is_special;
};
template <class A, class B>
auto foo(A& a, B& b) -> decltype(A::is_special, void())
{
cout << "specialized fallback" << endl;
}
Run Code Online (Sandbox Code Playgroud)
我想要的结果是:
int x;
string y;
float z;
string generic;
mine special;
foo(generic, x); // generic int
foo(generic, y); // generic string
foo(generic, z); // generic fallback
foo(special, x); // specialized fallback
foo(special, y); // specialized fallback
foo(special, z); // specialized fallback
Run Code Online (Sandbox Code Playgroud)
但是,上面的代码不起作用,因为对于特殊情况,存在模糊的重载.是否有任何简单的方法可以使这些函数只在A::is_special
不是有效类型时才被创建?理想情况下,我会用以下内容注释每个函数:
template <class A, class B>
auto foo(A& a, B& b) -> decltype(doesnt_work(A::is_special), void())
// ...
Run Code Online (Sandbox Code Playgroud)
在更一般的情况下,我也要问:鉴于任何"正面"SFINAE测试会导致测试结果导致函数或类被创建,是否有任何方法可以否定该测试专门用于其他情况?实质上,相当于if ... else if
SFINAE.
我没有得到这样的情况下工作,但我不得不重新命名所有foo
到foo_imp
,一个加long
参数,一般的,一个int
参数的专业之一,然后定义一个foo
调用它们(ideone代码在这里).这似乎不太理想,因为它不是那么简单,尽管无论如何我必须修改所有现有的foo
s.
[1]请注意,我不能使用类型的名称,因为它是一个嵌套模板,因此会导致不可导入的上下文.
实质上,相当于
if ... else if
SFINAE.
您可以使用额外参数手动控制重载决策:
template<int I> struct rank : rank<I-1> { static_assert(I > 0, ""); };
template<> struct rank<0> {};
template <class A, class B>
auto foo(A& a, B& b, rank<10>) -> /*some SFINAE */
{
}
template <class A, class B>
auto foo(A& a, B& b, rank<9>) -> /* some other SFINAE */
{
}
// ...
template <class A, class B>
void foo(A& a, B& b, rank<0>)
{
// fallback
}
template <class A, class B>
void foo(A& a, B& b) { return foo(a, b, rank<20>()); }
Run Code Online (Sandbox Code Playgroud)
具有最高"等级"的可行过载将通过过载分辨率来选择.
您不能直接否定临时 SFINAE约束("签名中使用的此表达式必须格式良好").您需要编写一个实际特征来检测它,然后否定结果.最简单的方法是使用 std::experimental::is_detected_v
,最近投票进入库基础知识TS的v2:
template<class T>
using is_special_t = decltype(T::is_special);
template <class A, class B>
auto foo(A& a, B& b) -> std::enable_if_t<!std::experimental::is_detected_v<is_special_t, A>>
{
cout << "generic fallback" << endl;
}
template <class A, class B>
auto foo(A& a, B& b) -> std::enable_if_t<std::experimental::is_detected_v<is_special_t, A>>
{
cout << "specialized fallback" << endl;
}
Run Code Online (Sandbox Code Playgroud)