连续调用enable_if重载时出错



基本上,我们的想法是为任何可迭代的东西重载operator <<,比如向量、列表和自定义类,它们正确地定义了begin((和迭代器方案。

最初,我编写了以下原型

template<template<class, class ...> class Container, class T, class ... Whatever>
std::ostream& operator<<(std::ostream& out, const Container<T, Whatever...>& container) { stuff }

问题是,我显然会与任何匹配模板定义的内容发生冲突,这些内容已经重载了<<,例如std::string。所以,如果我写cout << string { "Hello" },它是不明确的。我明白为什么。

因此,这个想法是激活上述过载,当且仅当运算符<lt;尚未定义。我选择以以下方式放弃std::enable_if的情况:

template<class> struct sfinae_true : std::true_type {};
template<class ToPrint> static auto test_insertion(int) -> sfinae_true<decltype(std::cout << std::declval<ToPrint>())>;
template<class ToPrint> static auto test_insertion(long) -> std::false_type;
template<class ToPrint> struct is_printable : decltype(test_insertion<ToPrint>(0)) {};
template<class ToPrint> using NotPrintable = std::enable_if_t<! is_printable<ToPrint>::value>;
//overload not availlable if operator<< is already defined (avoids ambiguity)
template<template<class, class ...> class Container, class T, class ... Whatever, NotPrintable<Container<T, Whatever...>>* = nullptr>
std::ostream& operator<<(std::ostream& out, const Container<T, Whatever...>& container)
{
//stuff
}

问题是,不知怎么的,至少在C++17中,我不能打印两次。也就是说,

vector<int> v1 = {1,2,3,4,5};    
vector<int> v2 = {6,7,8};
cout << v1 << endl;
cout << v2 << endl;

编译器告诉我没有运算符<lt;对于v2…难以置信,对吧?我不知道为什么,也不知道如何解决这个问题。

备注:我知道,我可以简单地将原型简化为template<class Container> std::ostream& operator<<(std::ostrea& out, const Container& c),但让我们说"我不想"。

要复制/粘贴的完整示例代码:

#include <iostream>
#include <type_traits>
#include <vector>
#include <string>
template<class> struct sfinae_true : std::true_type {};
template<class ToPrint> static auto test_insertion(int) -> sfinae_true<decltype(std::cout << std::declval<ToPrint>())>;
template<class ToPrint> static auto test_insertion(long) -> std::false_type;
template<class ToPrint> struct is_printable : decltype(test_insertion<ToPrint>(0)) {};
template<class ToPrint> using NotPrintable = std::enable_if_t<! is_printable<ToPrint>::value>;
//overload not availlable if operator<< is already defined (avoids ambiguity)
template<template<class, class ...> class Container, class T, class ... Whatever, NotPrintable<Container<T, Whatever...>>* = nullptr>
std::ostream& operator<<(std::ostream& out, const Container<T, Whatever...>& container)
{
out << "{ ";
auto it = container.begin();
auto it_end = container.end();
if(it != it_end)
{
out << *it;
++it;
}
for(; it != it_end; ++it)
out << " , " << (*it);
out << " }";
return out;
}
using namespace std;
int main()
{
vector<int> v1 = {1,2,3,4,5};    
vector<int> v2;       
cout << v1 << endl; //prints {1, 2, 3? 4, 5}
cout << v2 << endl; //compile error : no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘std::vector<int>’)

cout << string {"Hello"} << endl; //works fine
}

错误消息为

error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘std::vector<int>’)
cout << v2 << endl;

我使用g++(Ubuntu 7.5.0-3ubuntu1~18.04(7.5.0进行编译,使用命令g++ -o sample sample.cpp,其中sample.cpp是包含上述代码的文件。

好吧,所以基本上,我的编译器版本太旧了。在gcc 9.3上,它的工作原理与预期一致。

主题结束。(我读到,如果我没有足够的代表,我就无法结束我自己的主题,而我没有…(

最新更新