SFINAE 检测类型是否被定义
SFINAE detect if type is defined
我想在定义特定类型时选择模板的专业化。
我仍然无法理解 SFINAE :(。我可能很接近,也可能完全离开。我尝试了不同的东西,这是一些东西,我至少希望理解为什么它不起作用(is_complete
基本上是从 here 偷来的):
#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();
}
使用 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();
^
我想我或多或少知道出了什么问题:foo
不依赖于 T
,因此不需要替换来获得 foo
我得到了一个硬错误而不是不是错误。接下来我尝试使用
行的帮助程序
template <typename T>
struct make_foo_dependent {
using type = foo;
};
并尝试在 enable_if
中使用它,而不是直接在 foo
中使用它。但是,这只是增加了更多的错误,我没有在这里包含它,因为我担心这也是错误的方向。
如何根据是否定义了foo
来选择调用什么函数?如果未定义 foo
,使用 foo
的代码不应发出硬错误,而只是被编译器忽略。
PS:SFINAE 发生了很多变化,我发现很难找到将自己限制在 C++11 上的资源,C++11 的内容似乎比新标准要复杂一些。
是的,正如你所说,你应该根据模板参数T
制作test
;并且更好地制作两个重载模板。例如
// 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();
}
然后称它为
test(); // or test<foo>();
LIVE (foo is defined)
LIVE (foo is not defined)
顺便说一句:根据您的意图,我认为 test
的 return 类型应该是 typename std::enable_if<is_complete<T>::value,void>::type
而不是 std::enable_if<is_complete<foo>::value,void>
;这只是 std::enable_if
本身的实例化类型。
我想在定义特定类型时选择模板的专业化。
我仍然无法理解 SFINAE :(。我可能很接近,也可能完全离开。我尝试了不同的东西,这是一些东西,我至少希望理解为什么它不起作用(is_complete
基本上是从 here 偷来的):
#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();
}
使用 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();
^
我想我或多或少知道出了什么问题:foo
不依赖于 T
,因此不需要替换来获得 foo
我得到了一个硬错误而不是不是错误。接下来我尝试使用
template <typename T>
struct make_foo_dependent {
using type = foo;
};
并尝试在 enable_if
中使用它,而不是直接在 foo
中使用它。但是,这只是增加了更多的错误,我没有在这里包含它,因为我担心这也是错误的方向。
如何根据是否定义了foo
来选择调用什么函数?如果未定义 foo
,使用 foo
的代码不应发出硬错误,而只是被编译器忽略。
PS:SFINAE 发生了很多变化,我发现很难找到将自己限制在 C++11 上的资源,C++11 的内容似乎比新标准要复杂一些。
是的,正如你所说,你应该根据模板参数T
制作test
;并且更好地制作两个重载模板。例如
// 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();
}
然后称它为
test(); // or test<foo>();
LIVE (foo is defined)
LIVE (foo is not defined)
顺便说一句:根据您的意图,我认为 test
的 return 类型应该是 typename std::enable_if<is_complete<T>::value,void>::type
而不是 std::enable_if<is_complete<foo>::value,void>
;这只是 std::enable_if
本身的实例化类型。