C++ 罗素';C+中的s悖论+;模板

C++ 罗素';C+中的s悖论+;模板,c++,language-lawyer,template-meta-programming,C++,Language Lawyer,Template Meta Programming,考虑一下这个计划: #include <iostream> #include <type_traits> using namespace std; struct russell { template <typename barber, typename = typename enable_if<!is_convertible<barber, russell>::value>::type>

考虑一下这个计划:

#include <iostream>
#include <type_traits>

using namespace std;

struct russell {
    template <typename barber, 
              typename = typename enable_if<!is_convertible<barber, russell>::value>::type>
    russell(barber) {}
};

russell verify1() { return 42L; }
russell verify2() { return 42; }

int main ()
{
    verify1();
    verify2();
    cout << is_convertible<long, russell>::value;
    cout << is_convertible<int, russell>::value;
    return 0;
}
#包括
#包括
使用名称空间std;
罗素结构{
模板::类型>
罗素(理发师){}
};
russell verify1(){return 42L;}
russell verify2(){return 42;}
int main()
{
验证1();
验证2();

cout在重载解析期间,模板参数演绎必须实例化默认参数,以获得一组完整的模板参数来实例化函数模板(如果可能)因此,
的实例化是必要的,它在内部调用重载解析。
russell
中的构造函数模板在默认模板参数的实例化上下文中的作用域内

关键是
可转换::value
计算
russell
的默认模板参数,本身命名为
可转换::value

is_convertible<int, russell>::value
              |
              v
russell:russell(barber)
              |
              v
is_convertible<int, russell>::value (not in scope)
Clang默默地翻译了这一点。GCC抱怨无限递归链:它似乎认为
value
确实在默认参数的递归实例化的范围内,因此继续一次又一次地实例化
value
的初始值设定项。然而,可以说Clang是正确的,因为t和委托书中起草的相关短语,即PoI位于最近的随附声明之前。即,该声明不被视为部分实例化的一部分(尚未)如果你考虑上面的场景,有点有意义。为GCC解决问题:使用一个声明表单,在这个声明表单中,直到初始化器被实例化之后才声明。
enum {value = decltype(f<T>()){}};
enum{value=decltype(f()){};

这是用编译而成的。

@Barry yeah这看起来很傻。@Barry我偷偷地添加了我的答案,因为我看了很久,终于完成了答案。我可以重写它以适合你的问题,然后把它贴在那里,如果你认为这更明智的话。@Columbo我不知道什么更明智,但我很确定我会不管你决定做什么,我都会投你一票。甚至可能想扭转被骗的方向吗?@Barry我故意再次被骗,因为你的问题有着不可否认的相似之处。我会保持现状。
enum {value = decltype(f<T>()){}};