9

以下代码

#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:注意:不匹配的类型' '和' '

template<class T> bool operator==(foo<T>, foo<T>)

foo<T>std::nullptr_t

但是,如果我改用类中的定义,则代码将按预期工作。

让我说我理解错误信息:模板参数T不能被推断为类型nullptr(顺便说一句,decltype(*nullptr)不编译)。此外,这可以通过在类中定义函数来解决。

但是,出于统一的原因(我需要在外面定义其他友元函数),我想在类之外定义这个函数。

是否有一个“技巧”可以使函数的类外部定义起作用?

4

2 回答 2

5

There are three possible option for you

  • Declare and Define a new friend function with the type of rhs as std::nullptt_t

for ex

inline bool operator ==(foo<T> lhs, std::nullptr_t rhs) { return true; }
  • Or when equating the variable with nullptr, explicitly state the type of nullptr

for ex

assert(p == foo<int>(nullptr));
  • Declare and Define a new friend function with the type of rhs as void *

for ex

inline bool operator ==(foo<T> lhs, void *rhs) {         
    if (rhs == nullptr) 
        return true; 
    else
        return false;
    }
于 2012-04-29T20:35:41.403 回答
3

Abhijit 已经给了你基本的解决方案,但我想我会稍微解释一下,因为这是一个有趣的问题。

如果你在模板类中声明一个友元函数,像这样:

template <typename T>
struct A {
  friend void f(A);
};

那么你的意思是,任何以 A 作为参数的名为 f 的非模板函数都将成为 A 的朋友。所以你需要分别定义这些函数:

inline void f(A<int>) {...}
inline void f(A<float>) {...}
// etc.

尽管在类中定义它是一种快捷方式。

在这种情况下,没有办法为每个 T 创建一个定义友元 f(A) 的模板,因为您已经说过非模板函数是友元。事实上,它是一个非模板函数,使其在您的示例中可用,因为当编译器查找匹配函数时,非模板函数比模板函数允许更多的转换。

有一个相当通用的解决方法,虽然它有点混乱。您可以定义将处理您的 nullptr 的其他模板函数,或者您可能扔给它的任何其他内容,并将其推迟到您的主函数:

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);
}
于 2012-04-30T04:13:19.507 回答