我是模板编程的新手,我打算在这里使用该解决方案来确保所使用的类型已定义了运算符。但我想了解这段代码。我查看了cppreference的信息,但对它的工作方式更加困惑。
How to check whether operator== exists?
不幸的是,这对我来说是个神秘的事物,以为会询问代码中某些内容的含义和原因。
namespace CHECK
{
struct No {};
template <typename T, typename Arg>
No operator==(const T&, const Arg&);
/* Why are there two definitions of structures? Is this needed at all? Is
* there a simpler version of this whole code snippet?
*/
template <typename T, typename Arg = T>
struct EqualExists {
/* Why does this have to be a enum? What effect does this have? */
enum {
/* What happens if == sign is not defined for T? What would the
* below comparison return when true/false? (The comparison *(T*)(0) == *(Arg*)(0))
*
* What is the need for No here? Why is it needed and how will
* comparing it with the return type of == comparison be true ever?
* How can the return type of == comparison and No structure be the same?
*/
value = !std::is_same<decltype(*(T*)(0) == *(Arg*)(0)), No>::value
};
};
}
有人可以将其链接到原始问题吗?希望这可以帮助刚接触cpp的人也了解这一点。
答案 0 :(得分:2)
让我们按步骤进行分解:
(T*)(0)
:假装在地址0处有一个T
类型的对象;该子表达式的类型是一个指针*(T*)(0)
:假装在地址0处有一个T
类型的对象;由于前面的星号会取消引用指针,因此该子表达式的类型为引用。看起来有点像是对空指针的取消引用,但稍后会详细介绍。*(Arg*)(0)
:假装在地址0处有一个Arg
类型的对象;与T *(T*)(0) == *(Arg*)(0)
:这等效于使用letting the compiler figure out where the operator is defined的额外方便来调用operator==<T, Arg>( *(T*)(0), *(Arg*)(0) )
。
operator==
不存在,则将匹配CHECK
名称空间运算符。这是“全部捕获”模板。decltype(*(T*)(0) == *(Arg*)(0))
:decltype
说"don't execute the subexpression in the parentheses; just give me its type"。在这种情况下,类型是operator==
调用的返回类型。
std::is_same<decltype(*(T*)(0) == *(Arg*)(0)), No>::value
:如果类型相同,则std::is_same
的value
为true
,否则为false
。
::value
是静态constexpr bool decltype(...)
和结构CHECK::No
。operator==
通常返回bool。有时它可能返回用户定义的类型。不太可能有人编写自己的自定义operator==
来返回CHECK::No
,而此代码正是基于这种假设。enum { value = !std::is_same<...>::value }
:枚举始终是一个编译时常量,可在较旧的C ++编译器和规范(如C ++ 03,其中constexpr
不存在)上工作,并且与{{ 1}},并且不需要存储。
constexpr
应该是等效的。std::declval
是安全的选择。static constexpr bool value = !std::is_same<...>::value;
,这会愚弄检查者以为操作员未定义。CHECK::No operator==(const Foo&, const Bar&)
可能会遮盖全局定义的operator ==定义,从而导致假阴性。要解决上述问题并“简化”,一种方法是使用SFINAE。尽管“简单”在这里是主观的。
[edit]链接到工作版本:http://coliru.stacked-crooked.com/a/e9cc48729d53b6c6,并在下面更新了代码
operator==
[edit]我最初的答案有一个错误:在Exists计算中未使用模板args U和V,并且无法在gcc上编译。 (出于某些原因在msvc上工作)
template <typename T, typename Arg = T>
class EqualExists {
template <class U = T, class V = Arg, bool Exists = !!sizeof(std::declval<U>() == std::declval<V>())>
static std::true_type Func(const T&, const Arg&);
template <class U, class V>
static std::false_type Func(const U&, const V&);
public:
static constexpr bool value = decltype(Func(std::declval<T>(), std::declval<Arg>()))::value;
};