枚举和静态const成员变量在模板特征类中的用法

enum and static const member variable usage in template trait class

本文关键字:特征 用法 静态 const 成员 变量 枚举      更新时间:2023-10-16

我想通过查看是否提供了operator<<的过载来测试类是否可以流到ostream&。根据这些帖子,我尝试使用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;
}

但这无法编译:

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>();
然后一切都编译了。

为什么enumbool

之间有如此差异

valueStreamInsertionExists<T>中匿名名称的枚举。当您尝试这样做时:

std::cout << StreamInsertionExists<T>::value;

编译器在operator<<(std::ostream&, StreamInsertionExists<T>::E)上进行过载查找。在典型情况下,它会在enum上进行积分促销,并将其作为int流式传输。但是,您还定义了此操作员:

template<typename T> 
NotDefined& operator << (std::ostream&, const T&);

int版本更好地匹配CC_13版本(确切的匹配与积分促销),因此优先。是的,这是一个函数模板,但是仅当转换序列匹配时,非修正才是首选 - 在这种情况下,它们不符合。

因此,这线:

std::cout << TEST::StreamInsertionExists<A>::value << std::endl;

是:

operator<<(operator<<(std::cout, TEST::StreamInsertionExists<A>::value), std::endl);

和最内部的operator<<调用将使用您的NotDefined&模板。因此,下一步将是找到适当的功能呼叫:

operator<<(NotDefined&, std::endl);

operator<<没有这样的过载,因此错误。

如果将value更改为bool,则没有这样的问题,因为 operator<<完全将bool摄取:#6。也就是说,即使使用bool,您的特征仍然不正确,因为它总是返回false。您的NotDefined版本实际上返回参考,因此您必须对此进行检查。而且, NotDefined&表示不是定义的,因此您必须翻转符号:

static const bool value = !std::is_same<decltype(s << t), NotDefined&>();

但是,这特别容易出错。现在,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 { };