【发布时间】:2019-08-23 10:28:02
【问题描述】:
我想在定义某种类型时选择模板的特化。
我仍然无法理解 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,并且我得到一个硬错误而不是 Not An Error。接下来我尝试使用沿线的助手
template <typename T>
struct make_foo_dependent {
using type = foo;
};
并尝试在enable_if 中直接使用它而不是foo。但是,这只是增加了更多的错误,我没有在此处包含它,因为我担心这也朝着错误的方向发展。
如何根据是否定义foo来选择调用什么函数?如果未定义foo,则使用foo 的代码不应发出硬错误,而只是被编译器忽略。
PS:SFINAE 发生了很多变化,我发现很难找到将自己限制为 C++11 的资源,在这些资源中,情况似乎比新标准更复杂。
【问题讨论】:
-
"如果定义了 foo 就应该调用它" - 但
test();永远不会调用该函数,因为它是一个至少需要一个参数的模板。 -
@VTT 哦,对 :)。正如我所提到的,我在 SFINAE 上完全失败了,我只是尝试随机的东西,很少得到我想要的东西
-
The trick with
make_foo_dependentshould've worked。这其实是一个正确的方向。 -
@VTT 它编译,但它总是调用非模板
foo,我想它只能在基本情况也是模板时工作。不记得我从哪里得到它可以是非模板的想法 -
关心
struct is_complete和基于它的代码(SFINAE)。您可以快速进行 ODR 违规 NDR。
标签: c++ c++11 templates sfinae