Kon*_*lph 9 c++ templates c++11
以下代码
#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);
}
Run Code Online (Sandbox Code Playgroud)
无法使用错误消息进行编译
foo.cpp:18:5:错误:
operator==
'p == nullptr
'
in''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)
不编译).此外,这可以通过定义类中的函数来解决.
但是,出于统一的原因(我需要在外面定义其他友元函数),我想在类之外定义这个函数.
是否有一个"技巧"使函数的类外定义工作?
有三种可能的选择
std::nullptt_t
对于前
inline bool operator ==(foo<T> lhs, std::nullptr_t rhs) { return true; }
Run Code Online (Sandbox Code Playgroud)
nullptr
,明确说明类型nullptr
对于前
assert(p == foo<int>(nullptr));
Run Code Online (Sandbox Code Playgroud)
void *
对于前
inline bool operator ==(foo<T> lhs, void *rhs) {
if (rhs == nullptr)
return true;
else
return false;
}
Run Code Online (Sandbox Code Playgroud)
Abhijit 已经给了你基本的解决方案,但我想我应该稍微解释一下,因为这是一个有趣的问题。
如果您在模板类中声明一个友元函数,如下所示:
template <typename T>
struct A {
friend void f(A);
};
Run Code Online (Sandbox Code Playgroud)
那么你的意思是,任何以 A 作为参数的名为 f 的非模板函数都将是 A 的友元。因此,你需要单独定义这些函数:
inline void f(A<int>) {...}
inline void f(A<float>) {...}
// etc.
Run Code Online (Sandbox Code Playgroud)
尽管在类中定义它是一个快捷方式。
在这种情况下,无法制作一个为每个 T 定义友元 f(A) 的模板,因为您已经声明非模板函数才是友元。事实上,它是一个非模板函数,因此可以在您的示例中使用,因为当编译器查找匹配函数时,非模板函数比模板函数允许更多转换。
有一个相当通用的解决方法,尽管它有点混乱。您可以定义其他模板函数来处理您的 nullptr 或您可能抛出的任何其他内容,并将其推迟到您的 main 函数:
template <typename T>
inline bool operator ==(foo<T> lhs, std::nullptr_t rhs)
{
return lhs==foo<T>(rhs);
}
Run Code Online (Sandbox Code Playgroud)
为了对称,你可能想用两种方法来做:
template <typename T>
inline bool operator ==(std::nullptr_t lhs,foo<T> rhs)
{
return foo<T>(lhs)==rhs;
}
Run Code Online (Sandbox Code Playgroud)
另外,即使 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);
}
Run Code Online (Sandbox Code Playgroud)