以下代码
#include <cassert>
#include <cstddef>
template <typename T>
struct foo {
foo(std::nullptr_t) { }
//friend bool operator ==(foo lhs, foo rhs) { return true; }
template <typename U>
friend bool operator ==(foo<U> lhs, foo<U> rhs);
};
template <typename T>
inline bool operator ==(foo<T> lhs, foo<T> rhs) { return true; }
int main() {
foo<int> p = nullptr;
assert(p == nullptr);
}
无法编译并显示错误消息
foo.cpp:18:5:错误:“
operator==
”中的“p == nullptr
”不匹配 foo.cpp:18:5:注意:候选人是:
foo.cpp:14:13:注意:template<class T> bool operator==(foo<T>, foo<T>)
foo.cpp:14:13:注意:模板参数扣除/替换失败:
foo.cpp:18:5:注意:不匹配的类型“foo<T>
”和“std::nullptr_t
”
但是,如果我使用类中的定义,代码将按预期工作。
我要说我理解错误消息:无法推断出T
类型的模板参数nullptr
(顺便说一下,decltype(*nullptr)
没有' t编译)。此外,这可以通过在类中定义函数来解决。
但是,出于统一的原因(我还需要其他朋友函数来定义外部)我想在类之外定义这个函数。
是否有一个“技巧”来使函数的类定义外部工作?
答案 0 :(得分:5)
您有三种可能的选择
std::nullptt_t
for ex
inline bool operator ==(foo<T> lhs, std::nullptr_t rhs) { return true; }
nullptr
等同时,明确说明nullptr
的类型for ex
assert(p == foo<int>(nullptr));
void *
for ex
inline bool operator ==(foo<T> lhs, void *rhs) {
if (rhs == nullptr)
return true;
else
return false;
}
答案 1 :(得分:3)
Abhijit已经给了你基本的解决方案,但我想我会稍微阐述一下,因为这是一个有趣的问题。
如果在模板类中声明了友元函数,请执行以下操作:
template <typename T>
struct A {
friend void f(A);
};
那么你所说的是任何一个名为f的非模板函数,它将A作为参数将成为A的朋友。所以你需要分别定义这些函数:
inline void f(A<int>) {...}
inline void f(A<float>) {...}
// etc.
虽然在课堂内定义它是一种捷径。
在这种情况下,没有办法为每个T创建一个定义朋友f(A)的模板,因为你已经声明它是非模板函数是朋友。事实上,它是一个非模板函数,使其可用于您的示例,因为当编译器查找匹配函数时,非模板函数允许比模板函数更多的转换。
有一个相当一般的解决方法,虽然它有点凌乱。你可以定义其他模板函数来处理你的nullptr,或者你可能抛出的任何其他函数,只需将它推迟到你的main函数:
template <typename T>
inline bool operator ==(foo<T> lhs, std::nullptr_t rhs)
{
return lhs==foo<T>(rhs);
}
您可能希望以两种方式实现对称:
template <typename T>
inline bool operator ==(std::nullptr_t lhs,foo<T> rhs)
{
return foo<T>(lhs)==rhs;
}
另外,即使U和T不是同一类型,您定义好友函数的方式也会使operator==(foo<U>,foo<U>)
成为foo<T>
的朋友。它可能不会在实践中产生太大的影响,但有一种技术上更好的方法来做到这一点。它涉及向前声明模板函数,然后使模板参数的特化为朋友。
以下是一个完整的例子:
template <typename> struct foo;
template <typename T>
inline bool operator==(foo<T> lhs,foo<T> rhs);
template <typename T>
struct foo {
foo(std::nullptr_t) { }
friend bool operator==<>(foo lhs,foo rhs);
};
template <typename T>
inline bool operator ==(foo<T> lhs,foo<T> rhs)
{
return true;
}
template <typename T>
inline bool operator ==(foo<T> lhs, std::nullptr_t rhs)
{
return lhs==foo<T>(rhs);
}
template <typename T>
inline bool operator ==(std::null_ptr_t lhs,foo<T> rhs)
{
return foo<T>(lhs)==rhs;
}
int main() {
foo<int> p = nullptr;
assert(p == nullptr);
assert(nullptr == p);
assert(p == p);
}