我一直在寻找一种方法来限制模板类型参数实现给定签名的功能.我似乎已经达到了相当优雅的解决方案,允许自我记录代码和相当干净,类似概念的错误消息.唯一的问题是,我不确定这是否是有效的C或恰好在clang和
gcc中工作的东西.
这是代码:
#include <type_traits>
using std::enable_if;
// let's say we want something with a "regular" operator+
class Thing
{
public:
Thing operator+(const Thing&){return Thing();} //the kind of operator we want
};
class OtherThing
{
public:
OtherThing operator+(int){return OtherThing();} // the kind of operator we don't want
};
class YetAnotherThing
{
// no operator whatsoever
};
// The questionable line. I'm taking the address of the function and
// immediately discarding it using the comma operator.
#define HAS_FUNCTION(type, ret, name, args...) (static_cast<ret (type::*)(args)>(&type::name), 1)
#define T_HAS_OPERATOR_PLUS HAS_FUNCTION(T, T, operator+, const T&)
template <typename T>
typename enable_if<T_HAS_OPERATOR_PLUS>::type foo(T)
{
T t1, t2;
t1 + t2;
}
#undef T_HAS_OPERATOR_PLUS
int main()
{
Thing t;
OtherThing ot;
YetAnotherThing yat;
foo(t);
foo(ot);
foo(yat);
}
使用clang构建时,它会产生以下输出:
main.cpp:43:2: error: no matching function for call to 'foo'
foo(ot);
^~~
main.cpp:29:47: note: candidate template ignored: substitution failure [with T = OtherThing]: static_cast from 'OtherThing (OtherThing::*)(int)' to 'OtherThing (OtherThing::*)(const OtherThing &)' is not allowed
typename enable_if<T_HAS_OPERATOR_PLUS>::type foo(T)
~~~~~~~~~~~~~~~~~~~ ^
main.cpp:44:2: error: no matching function for call to 'foo'
foo(yat);
^~~
main.cpp:29:47: note: candidate template ignored: substitution failure [with T = YetAnotherThing]: no member named 'operator+' in 'YetAnotherThing'
typename enable_if<T_HAS_OPERATOR_PLUS>::type foo(T)
~~~~~~~~~~~~~~~~~~~ ^
2 errors generated.
……与通常的奥术暴风雪相比,它看起来相当不错.
所以,我的问题是:它在标准C 14中有效吗?毕竟我在编译时拿到了一个地址,似乎标准不允许这样的东西.
此外,由于我只是黑暗艺术的学徒,也许有一种更简单的方法来实现这一目标?
无论哪种方式,欢迎任何输入.提前致谢.
最佳答案 首先,boost TypeTraits有一个实现,你可以使用它而不必自己滚动 – 见
here.其次,你通常只想在有多个潜在的重载并且你想从候选集中删除一些时使用enable_if.如果你只是想强制执行T满足某些概念,那么使用static_assert会更加清晰.例如:
template <typename T>
auto foo(T)
{
static_assert(boost::has_plus<T, T>::value, "T must support operator+");
// Impl...
}