SFINAE检测类型是否已定义

for*_*818 4 c++ templates sfinae c++11

当定义某种类型时,我想选择一个模板的特殊化。

我仍然无法绕开SFINAE :(.。我可能已经接近或者可能已经完全离开了。我尝试了不同的方法,这是某种方法,我至少希望了解为什么它不起作用(is_complete基本上是从这里被盗):

#include <iostream>
#include <type_traits>

template <typename T, class = void>
struct is_complete : std::false_type {};

template <typename T> 
struct is_complete<T,decltype(void(sizeof(T)))> : std::true_type {};

// this should be called if foo is not defined
void test() { std::cout << "test base\n"; }

// forward declare foo
struct foo;

// this should be called if foo is defined    
template <typename T>
std::enable_if<is_complete<foo>::value,void> test() {
  foo::bar();
}

// this is either defined or not
struct foo{
  static void bar() { std::cout << "foo bar\n"; }
};

int main(){
  test();
}
Run Code Online (Sandbox Code Playgroud)

使用gcc 4.8(-std=c++11)我得到:

if_type_defined.cpp: In instantiation of ‘struct is_complete<foo>’:
if_type_defined.cpp:16:32:   required from here
if_type_defined.cpp:8:42: error: invalid application of ‘sizeof’ to incomplete type ‘foo’
 struct is_complete<T,decltype(void(sizeof(T)))> : std::true_type {};
                                          ^
if_type_defined.cpp:8:42: error: invalid application of ‘sizeof’ to incomplete type ‘foo’
if_type_defined.cpp: In function ‘std::enable_if<true, void> test()’:
if_type_defined.cpp:17:3: error: incomplete type ‘foo’ used in nested name specifier
   foo::bar();
   ^
Run Code Online (Sandbox Code Playgroud)

我想我或多或少知道什么地方出了问题:foo不依赖T,因此不需要替代就可以得到,foo而且我得到了一个硬错误而不是非错误。接下来,我尝试使用辅助工具

template <typename T>
struct make_foo_dependent { 
   using type = foo;
};
Run Code Online (Sandbox Code Playgroud)

并尝试在enable_if而不是foo直接内部使用它。但是,这只是增加了更多错误,我没有在此处添加它,因为恐怕这也会朝错误的方向发展。

如何根据foo定义的内容选择要调用的函数?如果foo未定义,则使用的代码foo不应发出硬错误,而应被编译器忽略。

PS:关于SFINAE的事情已经发生了很多变化,我发现很难找到将其自身限制为C ++ 11的资源,在这些资源中,似乎比新标准要麻烦一些。

son*_*yao 5

是的,正如您所说,您应该test根据template参数进行设置T;并更好地制作两个重载模板。例如

// this should be called if foo is not defined
template <typename T = foo>
typename std::enable_if<!is_complete<T>::value,void>::type test() { std::cout << "test base\n"; }

// this should be called if foo is defined    
template <typename T = foo>
typename std::enable_if<is_complete<T>::value,void>::type test() {
  T::bar();
}
Run Code Online (Sandbox Code Playgroud)

然后称它为

test(); // or test<foo>();
Run Code Online (Sandbox Code Playgroud)

LIVE(已定义foo)
LIVE(未定义foo)

顺便说一句:从您的意图来看,我认为的返回类型testtypename std::enable_if<is_complete<T>::value,void>::typestd::enable_if<is_complete<foo>::value,void>;这只是std::enable_if自身实例化的类型。