在类外定义的friend函数的模板上的隐式转换查找失败 [英] Implicit conversion lookup on template fails for friend function defined outside of class
问题描述
以下代码
#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:错误:没有匹配'
运算符==
'in'p == nullptr
'
foo.cpp:18:5:note:候选人是:
foo.cpp:14:13:note :template< class T> bool operator ==(foo< T>,foo< T>)
foo.cpp:14:13:note:template argument deduction / b $ b foo.cpp:18:5:note:不匹配的类型foo< T>
'和'std :: nullptr_t
'
foo.cpp:18:5: error: no match for '
operator==
' in 'p == nullptr
'
foo.cpp:18:5: note: candidate is:
foo.cpp:14:13: note:template<class T> bool operator==(foo<T>, foo<T>)
foo.cpp:14:13: note: template argument deduction/substitution failed:
foo.cpp:18:5: note: mismatched types 'foo<T>
' and 'std::nullptr_t
'
但是,如果我使用类中的定义,代码工作正常。
However, if I use the definition inside the class instead, the code works as expected.
让我说我了解错误讯息:,模板参数 T
nullptr
(顺便说一句, decltype(* nullptr)
不编译)。此外,这可以通过在类中定义函数来修复。
Let me say that I understand the error message: the template argument T
cannot be deduced for the type of nullptr
(incidentally, decltype(*nullptr)
doesn’t compile). Furthermore, this can be fixed here by just defining the function inside the class.
然而,出于一致性的原因(还有其他的朋友函数, / em>来定义外部)我想在类外定义这个函数。
However, for reasons of uniformity (there are other friend functions which I need to define outside) I would like to define this function outside of the class.
有一个技巧的功能工作?
推荐答案
Abhijit已经给了你基本的解决方案,
Abhijit has already given you the basic solution, but I thought I would expound upon it a bit since this is an interesting problem.
如果你在模板类中声明一个友元函数,像这样:
If you declare a friend function inside a template class, like this:
template <typename T>
struct A {
friend void f(A);
};
然后你说的是任何非模板函数f,它以A作为参数因此你需要分别定义这些函数:
Then what you are saying is that any non-template function called f that takes A as a parameter will be a friend of A. So you would need to define these functions separately:
inline void f(A<int>) {...}
inline void f(A<float>) {...}
// etc.
虽然在类中定义它是一个快捷方式。
Although defining it inside the class is a shortcut.
在这种情况下,没有办法定义一个模板来定义朋友f(A)对于每个T,因为你已经说明它是非模板函数是朋友。它是一个非模板函数,使其可用于您的示例,因为非模板函数允许比编译器查找匹配的函数时更多的转换比模板函数。
In this case, there is no way to make a template that defines the friend f(A) for every T, because you've already stated that it is the non-template function that is the friend. It is the very fact that it is a non-template function that makes it usable in your example, because non-template functions allow more conversions than template functions when the compiler looks for matching functions.
有一个相当一般的解决方法,虽然有点凌乱。你可以定义其他模板函数来处理你的nullptr,或者你可能抛出的任何东西,只是将它推迟到你的主要函数:
There is a fairly general workaround, although it is a bit messy. You can define other template functions that will handle your nullptr, or whatever else you might throw at it, and just defer it to your main function:
template <typename T>
inline bool operator ==(foo<T> lhs, std::nullptr_t rhs)
{
return lhs==foo<T>(rhs);
}
您可能希望以两种方式进行对称:
You may want to do it both ways for symmetry:
template <typename T>
inline bool operator ==(std::nullptr_t lhs,foo<T> rhs)
{
return foo<T>(lhs)==rhs;
}
另一个注意事项, code> operator ==(foo< U>,foo< U>)的朋友 foo< T>
T不是相同的类型。它可能不会在实践中产生很大的不同,但有一个技术上更好的方法来做到这一点。
On a separate note, the way you've defined your friend function makes operator==(foo<U>,foo<U>)
a friend of foo<T>
even when U and T are not the same types. It probably isn't going to make much difference in practice, but there is a technically better way to do this. It involves forward declaring the template function, and then making the specialization for your template parameter be a friend.
这里是一个完整的例子:
Here is a full example:
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);
}
这篇关于在类外定义的friend函数的模板上的隐式转换查找失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!