【发布时间】:2012-07-17 22:58:00
【问题描述】:
我是编写模板元编程代码的新手(而不是仅仅阅读它)。所以我遇到了一些菜鸟问题。这篇名为 "What happened to my SFINAE?" 的非 SO 帖子很好地总结了其中一个,我将 C++11 化为:
(注意:我给这些方法提供了不同的名称,只是为了帮助我在这个“思想实验”示例中进行错误诊断。请参阅@R.MartinhoFernandes's notes,了解为什么您实际上不会在实践中为非重载选择这种方法.)
#include <type_traits>
using namespace std;
template <typename T>
struct Foo {
typename enable_if<is_pointer<T>::value, void>::type
valid_if_pointer(T) const { }
typename disable_if<is_pointer<T>::value, void>::type
valid_if_not_pointer(T) const { }
};
int main(int argc, char * argv[])
{
int someInt = 1020;
Foo<int*>().valid_if_pointer(&someInt);
Foo<int>().valid_if_not_pointer(304);
return 0;
}
@Alf 说 SFINAE 发生的事情是“它一开始就不存在”,并给出了编译的建议,但模板化的是函数而不是类。这在某些情况下可能是正确的,但并非全部。 (例如:我正在专门尝试编写一个容器,该容器可以容纳可能是也可能不是可复制构造的类型,我需要基于此来打开和关闭方法。)
作为一种解决方法,我试了一下……它似乎可以正常工作。
#include <type_traits>
using namespace std;
template <typename T>
struct FooPointerBase {
void valid_if_pointer(T) const { }
};
template <typename T>
struct FooNonPointerBase {
void valid_if_not_pointer(T) const { }
};
template <typename T>
struct Foo : public conditional<
is_pointer<T>::value,
FooPointerBase<T>,
FooNonPointerBase<T> >::type {
};
int main(int argc, char * argv[])
{
int someInt = 1020;
#if DEMONSTRATE_ERROR_CASES
Foo<int*>().valid_if_not_pointer(&someInt);
Foo<int>().valid_if_pointer(304);
#else
Foo<int*>().valid_if_pointer(&someInt);
Foo<int>().valid_if_not_pointer(304);
#endif
return 0;
}
但是如果这没有被破坏(是吗?),它肯定没有遵循一个好的通用方法来基于嗅探特征类型来打开和关闭模板化类中的方法。有没有更好的解决方案?
【问题讨论】:
-
"这可能适用于某些情况,但并非全部。"老实说,我能想到的唯一情况是你想要一个稳定的二进制接口。无论如何,不,我认为没有更好的解决方案。
-
@R.MartinhoFernandes 我很困惑......你认为嗅探其包含类型的类型特征的容器几乎没有适用性,并且基于嗅探打开和关闭不同的方法? (我会引用 boost::optional 应用于可移动类型,因为我正在研究这个和一些相关问题。) 你是说你认为没有比我更好的解决方案想出了,或者您认为没有比 Alf 的去模板化类型更好的解决方案? :-/
-
@HostileFork 我认为没有比模板化功能或您的功能更好的解决方案了。两者都很好,我更喜欢对函数进行模板化(就像下面的 Flexo 所做的那样),因为一般来说,它不太麻烦(什么?一对新类针对每个标准?)。是的,您的用例非常好。我只是认为除非您提供两个重载,否则不需要 SFINAE。实际上,我认为 SFINAE 更糟糕。给我一点时间,我认为这更适合答案;)
标签: c++ c++11 template-meta-programming sfinae typetraits