Hsu*_*Hau 5 c++ templates overload-resolution c++11
我想ostream&
通过查看是否提供了重载来测试类是否可以流式传输operator<<
.根据这些 帖子,我尝试使用C++ 11编写另一个版本.这是我的尝试:
#include <iostream>
#include <type_traits>
namespace TEST{
class NotDefined{};
template<typename T>
NotDefined& operator << (::std::ostream&, const T&);
template <typename T>
struct StreamInsertionExists {
static std::ostream &s;
static T const &t;
enum { value = std::is_same<decltype(s << t), NotDefined>() };
};
}
struct A{
int val;
friend ::std::ostream& operator<<(::std::ostream&, const A&);
};
::std::ostream& operator<<(::std::ostream& os, const A& a)
{
os << a.val;
return os;
}
struct B{};
int main() {
std::cout << TEST::StreamInsertionExists<A>::value << std::endl;
std::cout << TEST::StreamInsertionExists<B>::value << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
但这无法编译:
Run Code Online (Sandbox Code Playgroud)test_oper.cpp:40:57: error: reference to overloaded function could not be resolved; did you mean to call it? std::cout << TEST::StreamInsertionExists<A>::value << std::endl; /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:1020:1: note: possible target for call endl(basic_ostream<_CharT, _Traits>& __os) test_oper.cpp:30:17: note: candidate function not viable: no known conversion from 'TEST::NotDefined' to '::std::ostream &' (aka 'basic_ostream<char> &') for 1st argument ::std::ostream& operator<<(::std::ostream& os, const A& a) test_oper.cpp:15:15: note: candidate template ignored: couldn't infer template argument 'T' NotDefined& operator << (::std::ostream&, const T&);
但是,如果我更换线路
enum { value = std::is_same<decltype(s << t), NotDefined>() };
,
static const bool value = std::is_same<decltype(s << t), NotDefined>();
那么一切都会编译.
为什么enum
和bool
?之间存在这样的差异?
value
是 中匿名名称的枚举StreamInsertionExists<T>
。当你尝试这样做时:
std::cout << StreamInsertionExists<T>::value;
Run Code Online (Sandbox Code Playgroud)
编译器正在对 进行重载查找operator<<(std::ostream&, StreamInsertionExists<T>::E)
。在典型情况下,它会在 上进行积分推广enum
并将其流式传输为int
。但是,您还定义了此运算符:
template<typename T>
NotDefined& operator << (std::ostream&, const T&);
Run Code Online (Sandbox Code Playgroud)
enum
这是比版本更好的匹配int
(精确匹配与积分提升),因此是首选。是的,它是一个函数模板,但只有当转换序列匹配时才首选非模板 - 在这种情况下它们不匹配。
因此,这一行:
std::cout << TEST::StreamInsertionExists<A>::value << std::endl;
Run Code Online (Sandbox Code Playgroud)
这是:
operator<<(operator<<(std::cout, TEST::StreamInsertionExists<A>::value), std::endl);
Run Code Online (Sandbox Code Playgroud)
最里面的operator<<
调用将使用您的NotDefined&
模板。因此,下一步是找到合适的函数调用:
operator<<(NotDefined&, std::endl);
Run Code Online (Sandbox Code Playgroud)
并且不存在这样的过载,因此会出现operator<<
错误。
如果你改为value
be bool
,就不存在这样的问题,因为有一个恰好operator<<
需要bool
:#6。也就是说,即使有bool
,你的特质仍然不正确,因为它总是返回false
。您的NotDefined
版本实际上返回了一个引用,因此您必须对此进行检查。而且,NotDefined&
意思没有定义,所以你必须翻转符号:
static const bool value = !std::is_same<decltype(s << t), NotDefined&>();
Run Code Online (Sandbox Code Playgroud)
然而,这特别容易出错。现在cout << B{};
,不是编译失败,而是给您一个链接器错误,并cout << B{} << endl;
给您带来同样令人困惑的重载错误endl
,而不是简单地声明您无法流式传输B
.
你应该更喜欢这样做:
template <typename...>
using void_t = void;
template <typename T, typename = void>
struct stream_insertion_exists : std::false_type { };
template <typename T>
struct stream_insertion_exists<T, void_t<
decltype(std::declval<std::ostream&>() << std::declval<T>())
> > : std::true_type { };
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
472 次 |
最近记录: |