ostream&的显式模板参数规范运算符<<困惑的编译错误 [英] explicit template parameter specification for ostream& operator<< puzzling compile error

查看:416
本文介绍了ostream&的显式模板参数规范运算符<<困惑的编译错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

  #include< iostream> 
//#include< algorithm> //编译错误,当`g ++ -std = c ++ 11`,否则

使用namespace std;

template< typename T>
class Foo
{
T x_;
public:
Foo(const T& x = {}):x_(x){}; // default ctor,bounded rvalue default-initialized

template< typename S>
friend ostream&运算符<<(ostream& lhs,const Foo& rhs)
{
return lhs< rhs.x_;
}
};

int main()
{
Foo< double> foo(10.1);
cout<< foo< endl;
operator<<(cout,foo)<< endl;

//#include< algorithm>时,编译时错误。并用`g ++ -std = c ++ 11`编译
//,否则很好(包括clang ++和g ++)
operator<< < double>(cout,foo)< endl;
}

一切都编译正常,但如果我 #include< algorithm> ,并使用 g ++ -std = c ++ 11 编译,我得到一个非常混乱的编译错误到 std :: uniform_int_distribution ?!?!)。它发生在最后一行,当我为运算符< 的调用明确指定类型 double

无论 -std = c ++ 11

clang ++ / code>标志,以及没有 -std = c ++ 11 标志的 g ++ 这里发生了什么?我真的不知道,我以某种方式重载在算法中定义的全局<
这是一个 g ++ 错误? (我使用g ++ 4.9 btw)。

 在/ opt / local / include / gcc49 / c ++ / random :49:0,
来自/opt/local/include/gcc49/c++/bits/stl_algo.h:66,
来自/ opt / local / include / gcc49 / c ++ / algorithm:62,
从/Users/vlad/minimal.cpp:2:
/opt/local/include/gcc49/c++/bits/random.h:在'class std :: uniform_int_distribution< double>'的实例化中:
/Users/vlad/minimal.cpp:25:34:递归需要替换'template< class _IntType,class _CharT,class _Traits> std :: basic_ostream< _CharT,_Traits>& std :: operator<<(std :: basic_ostream< _CharT,_Traits>& const std :: uniform_int_distribution< _IntType>&)[with _IntType = double; _CharT = char; _Traits = std :: char_traits< char>]'
/Users/vlad/minimal.cpp:25:34:从这里需要
/ opt / local / include / gcc49 / c ++ / bits / random。 h:1668:7:error:static assertion failed:模板参数不是一个整数类型
static_assert(std :: is_integral< _IntType> :: value,
^
/ opt / local / include /gcc49/c++/bits/random.h:'class std :: geometry_distribution< double>'的实例化:
/Users/vlad/minimal.cpp:25:34:递归需要'template'类_IntType,类_CharT,类_Traits> std :: basic_ostream< _CharT,_Traits>& std :: operator<<(std :: basic_ostream< _CharT,_Traits&>& const std :: geometric_distribution< _IntType& )[with _IntType = double; _CharT = char; _Traits = std :: char_traits< char>]'
/Users/vlad/minimal.cpp:25:34:需要从这里
/ opt / local /include/gcc49/c++/bits/random.h:4010:7:error:static assertion failed:template argument not an integral type
static_assert(std :: is_integral< _IntType> :: value,
^
/opt/local/include/gcc49/c++/bits/random.h:'class std :: negative_binomial_distribution< double>'的实例化:
/Users/vlad/minimal.cpp:25 :34:通过替换'template< class _IntType,class _CharT,class _Traits>递归地需要。 std :: basic_ostream< _CharT,_Traits>& std :: operator<<<(std :: basic_ostream< _CharT,_Traits>& const std :: negative_binomial_distribution< _IntType>&)[with _IntType = double; _CharT = char; _Traits = std :: char_traits< char>]'
/Users/vlad/minimal.cpp:25:34:从这里需要
/ opt / local / include / gcc49 / c ++ / bits / random。 h:4210:7:error:static assertion failed:模板参数不是一个整数类型
static_assert(std :: is_integral< _IntType> :: value,
^
/ opt / local / include /gcc49/c++/bits/random.h:'class std :: poisson_distribution< double>'的实例化:
/Users/vlad/minimal.cpp:25:34:递归需要'template'类_IntType,类_CharT,类_Traits> std :: basic_ostream< _CharT,_Traits& std :: operator<<(std :: basic_ostream< _CharT,_Traits>& const std :: poisson_distribution< _IntType& )[with _IntType = double; _CharT = char; _Traits = std :: char_traits< char>]'
/Users/vlad/minimal.cpp:25:34:需要从这里
/ opt / local /include/gcc49/c++/bits/random.h:4432:7:error:static assertion failed:template argument not an integral type
static_assert(std :: is_integral< _IntType> :: value,
^
/opt/local/include/gcc49/c++/bits/random.h:在'class std :: binomial_distribution< double>'的实例化中:
/Users/vlad/minimal.cpp:25 :34:通过替换'template< class _IntType,class _CharT,class _Traits>递归地需要。 std :: basic_ostream< _CharT,_Traits>& std :: operator<<<(std :: basic_ostream< _CharT,_Traits>& const std :: binomial_distribution< _IntType>&)[with _IntType = double; _CharT = char; _Traits = std :: char_traits< char>]'
/Users/vlad/minimal.cpp:25:34:从这里需要
/ opt / local / include / gcc49 / c ++ / bits / random。 h:3779:7:error:static assertion failed:模板参数不是一个整数类型
static_assert(std :: is_integral< _IntType> :: value,
^
/ opt / local / include /gcc49/c++/bits/random.h:'class std :: discrete_distribution< double>'的实例化:
/Users/vlad/minimal.cpp:25:34:递归需要'template'类_IntType,类_CharT,类_Traits> std :: basic_ostream< _CharT,_Traits& std :: operator<<<(std :: basic_ostream< _CharT,_Traits&>& const std :: discrete_distribution< _IntType& )[with _IntType = double; _CharT = char; _Traits = std :: char_traits< char>]'
/Users/vlad/minimal.cpp:25:34:需要从这里
/ opt / local /include/gcc49/c++/bits/random.h:5253:7:error:static assertion failed:模板参数不是一个整数类型
static_assert(std :: is_integral< _IntType> :: value,
^


解决方案

我认为归结为: p>

  #include< type_traits> 

template< class T>
struct foo
{
static_assert(std :: is_integral< T> {},T必须是整数);
};

template< class T> struct bar {};

template< class T,class Stream>
Stream& operator<<(Stream& p,foo< T> const&

template< class T,class Stream>
Stream& operator<<(Stream& p,bar< T> const&

int main()
{
int x;
operator<< < double>(x,1.0);请注意,在libstdc ++的实现中,第一个模板参数显式地传递给了<$ c(


$ b < $ c> operator<<
用作分布的模板参数(在OP中)。所以在理论上,从运算符<调用的第二个函数参数到分布类型的隐式转换是可能的。



在检查歧义之前,重载解析必须实例化类模板,以检查转换构造函数:如果有任何,如果它们是显式的,也就是说,如果转换是可行的/ em>。



实例化非整数类的类模板是一个错误,由 static_assert 。因此,在选择一个重载之前,编译器会提示实例化。



如果编译器不需要选择重载, [temp.inst] / 7。所有其他重载需要一个用户定义的转换(参数类型是一个类,不同于参数类型),而在OP中定义为friend函数的重载是完全匹配。



不是实例化不需要的类模板是某种优化 - 它不是强制性的。 clang ++似乎在这里执行它,g ++不(并实例化类模板)。有关另一个示例和一些讨论,请参见 gcc和clang之间的C ++不一致


I have the following code:

#include <iostream>
//#include <algorithm> // compile error when `g++ -std=c++11`, fine otherwise

using namespace std;

template<typename T>
class Foo
{
    T x_;
public:
    Foo(const T& x={}): x_(x){}; // default ctor, bounded rvalue default-initialized

    template<typename S>
    friend ostream& operator<<(ostream& lhs, const Foo<S>& rhs)
    {
        return lhs << rhs.x_;
    }
};

int main()
{
    Foo<double> foo(10.1);
    cout << foo << endl;
    operator<<(cout, foo) << endl;

    //puzzling compile-time error when #include<algorithm> and compile 
    // with `g++ -std=c++11`, otherwise fine (both clang++ and g++)
    operator<< <double>(cout, foo) << endl; 
}

Everything compiles and works fine, however, if I #include<algorithm>, and compile with g++ -std=c++11, I get a very messy compile error (see below, related to std::uniform_int_distribution?!?!). It happens on the last line, when I explicitly specify the type double for the call to operator<<.

It works though on clang++ regardless of the -std=c++11 flag, and also on g++ without the -std=c++11 flag. What is happening here? I really have no idea, am I overloading somehow the global << defined in algorithm? Is this a g++ bug? (I use g++4.9 btw).

In file included from /opt/local/include/gcc49/c++/random:49:0,
                 from /opt/local/include/gcc49/c++/bits/stl_algo.h:66,
                 from /opt/local/include/gcc49/c++/algorithm:62,
                 from /Users/vlad/minimal.cpp:2:
/opt/local/include/gcc49/c++/bits/random.h: In instantiation of 'class std::uniform_int_distribution<double>':
/Users/vlad/minimal.cpp:25:34:   recursively required by substitution of 'template<class _IntType, class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::uniform_int_distribution<_IntType>&) [with _IntType = double; _CharT = char; _Traits = std::char_traits<char>]'
/Users/vlad/minimal.cpp:25:34:   required from here
/opt/local/include/gcc49/c++/bits/random.h:1668:7: error: static assertion failed: template argument not an integral type
       static_assert(std::is_integral<_IntType>::value,
       ^
/opt/local/include/gcc49/c++/bits/random.h: In instantiation of 'class std::geometric_distribution<double>':
/Users/vlad/minimal.cpp:25:34:   recursively required by substitution of 'template<class _IntType, class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::geometric_distribution<_IntType>&) [with _IntType = double; _CharT = char; _Traits = std::char_traits<char>]'
/Users/vlad/minimal.cpp:25:34:   required from here
/opt/local/include/gcc49/c++/bits/random.h:4010:7: error: static assertion failed: template argument not an integral type
       static_assert(std::is_integral<_IntType>::value,
       ^
/opt/local/include/gcc49/c++/bits/random.h: In instantiation of 'class std::negative_binomial_distribution<double>':
/Users/vlad/minimal.cpp:25:34:   recursively required by substitution of 'template<class _IntType, class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::negative_binomial_distribution<_IntType>&) [with _IntType = double; _CharT = char; _Traits = std::char_traits<char>]'
/Users/vlad/minimal.cpp:25:34:   required from here
/opt/local/include/gcc49/c++/bits/random.h:4210:7: error: static assertion failed: template argument not an integral type
       static_assert(std::is_integral<_IntType>::value,
       ^
/opt/local/include/gcc49/c++/bits/random.h: In instantiation of 'class std::poisson_distribution<double>':
/Users/vlad/minimal.cpp:25:34:   recursively required by substitution of 'template<class _IntType, class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::poisson_distribution<_IntType>&) [with _IntType = double; _CharT = char; _Traits = std::char_traits<char>]'
/Users/vlad/minimal.cpp:25:34:   required from here
/opt/local/include/gcc49/c++/bits/random.h:4432:7: error: static assertion failed: template argument not an integral type
       static_assert(std::is_integral<_IntType>::value,
       ^
/opt/local/include/gcc49/c++/bits/random.h: In instantiation of 'class std::binomial_distribution<double>':
/Users/vlad/minimal.cpp:25:34:   recursively required by substitution of 'template<class _IntType, class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::binomial_distribution<_IntType>&) [with _IntType = double; _CharT = char; _Traits = std::char_traits<char>]'
/Users/vlad/minimal.cpp:25:34:   required from here
/opt/local/include/gcc49/c++/bits/random.h:3779:7: error: static assertion failed: template argument not an integral type
       static_assert(std::is_integral<_IntType>::value,
       ^
/opt/local/include/gcc49/c++/bits/random.h: In instantiation of 'class std::discrete_distribution<double>':
/Users/vlad/minimal.cpp:25:34:   recursively required by substitution of 'template<class _IntType, class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::discrete_distribution<_IntType>&) [with _IntType = double; _CharT = char; _Traits = std::char_traits<char>]'
/Users/vlad/minimal.cpp:25:34:   required from here
/opt/local/include/gcc49/c++/bits/random.h:5253:7: error: static assertion failed: template argument not an integral type
       static_assert(std::is_integral<_IntType>::value,
       ^

解决方案

I think it boils down to this:

#include <type_traits>

template<class T>
struct foo
{
    static_assert(std::is_integral<T>{}, "T must be integral");
};

template<class T> struct bar {};

template<class T, class Stream>
Stream& operator<<(Stream& p, foo<T> const&);

template<class T, class Stream>
Stream& operator<<(Stream& p, bar<T> const&);

int main()
{
    int x;
    operator<< <double>(x, 1.0);
}

Note that in libstdc++'s implementation, the first template argument explicitly passed to operator<< is used as the template argument for the distribution (in the OP). So in theory, an implicit conversion from the second function argument of the operator<< call to the distribution type is possible.

Before checking for ambiguity, overloading resolution has to instantiate the class templates in order to check for converting constructors: If there are any, if they're explicit etc -- that is, if the conversion is viable.

Instantiating the class template for a non-integral type however is an error, checked by static_assert. So before one of the overload is selected, the compiler complains about the instantiation.

This instantiation is not strictly required if the compiler does not need it to select an overload, see [temp.inst]/7. All other overloads require a User-Defined Conversion (the parameter type is a class and different from the argument type), whereas the overload defined as friend function in the OP is an Exact Match. So checking for the viability of those other conversions is not required, those overloads won't be selected anyway.

Not instantiating the not required class templates is some kind of optimization - it is not mandatory. clang++ seems to perform it here, g++ doesn't (and instantiates the class templates). For another example and some discussion, see C++ inconsistency between gcc and clang

这篇关于ostream&amp;的显式模板参数规范运算符&lt;&lt;困惑的编译错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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