专门化运算符的最佳方法<<对于具有通用模板功能的std :: ostream和std :: vector? [英] Best way to specialise operator<< for std::ostream and std::vector with generic template functions?

查看:144
本文介绍了专门化运算符的最佳方法<<对于具有通用模板功能的std :: ostream和std :: vector?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了标准指定的两阶段查找问题,并且(正确)由clang实现了std::ostreamstd::vectoroperator<<重载.

I am having trouble with the two-phase look-up as specified by the standard and (correctly) implemented by clang in connection with an overload of operator<< for std::ostream and std::vector.

考虑一个非常通用的模板函数,该函数将其参数转换为流(仅对递归非常有用,但简单的示例足以触发问题):

Consider a very generic template function which shifts its argument into a stream (really useful only with recursion, but the simple example is enough to trigger the problem):

// generic.h
template<typename Stream, typename Arg>
void shift(Stream& s, Arg& arg) { s << arg; }

此generic.h可以在整个项目中使用.然后在其他文件中,我们要输出std::vector,因此我们定义了一个重载

This generic.h may be used throughout a project. Then in some other file, we want to output a std::vector, so we define an overload

// vector.h
#include <iostream>
#include <vector>
std::ostream& operator<<(std::ostream& s, std::vector<int> const& v) {
  for(auto const& elem : v) { s << elem << ", "; }
  return s;
}

和主文件一样,我们首先(间接)使用generic.h,然后由于其他一些包含,导致向量重载:

And the main file, we firstly (indirectly) use the generic.h and then, due to some other include, the vector overload:

// main.cpp
#include "generic.h"
#include "vector.h"

int main() {
  std::vector<int> v{1,2,3,4,5};
  shift(std::cout, v);
}

此代码已被GCC(5.4.0)和ICC(16.0)接受,但是clang抱怨call to function 'operator<<' that is neither visible in the template definition nor found by argument-dependent lookup.

This code is accepted by GCC (5.4.0) and ICC (16.0), but clang complains call to function 'operator<<' that is neither visible in the template definition nor found by argument-dependent lookup.

令人讨厌的是,clang是正确的,我想在我的代码中修复它.据我所知,共有三个选项:

The annoying thing is that clang is right and I’d like to fix this in my code. There are as far as I can see three options:

  • shift()之前移动operator<<的定义.这样做的缺点是,当包含间接包含generic.hvector.h的某些文件(可能是其他文件)时,还必须注意正确地对它们进行排序.

  • Move the definition of operator<< before shift(). This has the disadvantage that when including some (possibly other) files which indirectly include generic.h and vector.h, one would also have to take care to order them correctly.

使用自定义名称空间,将std所需的所有内容导入该名称空间,并在该名称空间内的new-namespace类上定义运算符,以便ADL可以找到它.

Use a custom namespace, import everything needed from std into that namespace and define the operator on the new-namespace classes inside that namespace, so that ADL can find it.

std命名空间中定义operator<<.我认为这是不确定的行为.

Define operator<< in the std namespace. I think this is undefined behaviour.

我错过了任何选择吗?通常,为仅std类的函数定义重载的最佳方法是什么(如果我想移动NS::MyClass则不存在此问题,因为这样我就可以在NS中定义运算符了.)

Did I miss any option? What would be the best way in general to define overloads for functions of std-only classes (the issue does not exist if I want to shift NS::MyClass, since then I can just define the operator in NS).

推荐答案

不要为您无法控制的类型重载运算符,例如:

Don't overload operators for types you don't control, such as:

std::ostream& operator<<(std::ostream& s, std::vector<int> const& v);

相反,创建一个纤巧的适配器类并为其定义运算符,例如:

Instead create a tiny adaptor class and define the operator for that, for example:

template<typename T> struct PrintableVector {
  std::vector<T> const* vec;
}

template<typename T>
std::ostream& operator<<(std::ostream& s, PrintableVector<T> v) {
  for(auto const& elem : *v.vec) { s << elem << ", "; }
  return s;
}

可以这样使用:

shift(std::cout, PrintableVector<int>{&v});

您可以将适配器放在所需的任何名称空间中,并将重载的运算符放在相同的名称空间中,以便ADL可以找到它.

You can put the adaptor in whatever namespace you like, and put the overloaded operator in the same namespace so it can be found by ADL.

这样可以避免查找问题,不需要向名称空间std中添加任何内容,也不会尝试唯一地定义打印vector<int>的含义(这可能会导致程序其他部分出现问题)其他代码假定向量不可打印,或尝试为其定义自己的重载.

That avoids lookup problems, doesn't require adding anything to namespace std, and doesn't try to uniquely define what it means to print a vector<int> (which might cause problems in other parts of the program if some other code assumes vectors are not printable, or tries to define its own overloads for them).

这篇关于专门化运算符的最佳方法&lt;&lt;对于具有通用模板功能的std :: ostream和std :: vector?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆