C ++ 14模板部分特化不可见

时间:2017-04-08 23:15:05

标签: c++ c++14 iostream template-meta-programming

我试图理解为什么模板部分特化变得不可见。

我正在做一个小例子,说明我如何达到下面的错误。 该示例尝试重载operator<<以打印到ostreams。 有一个解决方案适用于问题1,用于打印元组。我的问题是为什么下面的那个因为看不见的错误而失败。

来自clang的完整错误:

call to function 'operator<<' that is neither visible in the template definition nor found by argument-dependent
      lookup
        operator<<(os, std::get<0>(t));
        ^
testing.cpp:9:47: note: in instantiation of member function 'tuple_printer<1, std::__1::tuple<std::__1::tuple<const char *, int> > >::print'
      requested here
        tuple_printer<s-1, std::tuple<T...>>::print(os, t);
                                              ^
testing.cpp:33:52: note: in instantiation of member function 'tuple_printer<2, std::__1::tuple<const char *, int> >::print' requested here
    tuple_printer<sizeof...(T), std::tuple<T...>>::print(os, t);
                                                   ^
testing.cpp:40:15: note: in instantiation of function template specialization 'operator<<<const char *, int>' requested here
    std::cout << std::make_tuple("hello", 5) << std::endl;
              ^
testing.cpp:30:15: note: 'operator<<' should be declared prior to the call site
std::ostream& operator<<(std::ostream& os, const std::tuple<T...>& t)

示例代码:

#include <tuple>
#include <iostream>

template<size_t s, typename... T>
struct tuple_printer{
    static void print(std::ostream& os, const std::tuple<T...>& t){
        os << ", ";
        os << std::get<s-1>(t);
        tuple_printer<s-1, std::tuple<T...>>::print(os, t);
    }
};

template<typename... T>
struct tuple_printer<0, T...>{
    static void print(std::ostream& os, const std::tuple<T...>& t){
        //nothing to do here
    }
};

template<typename... T>
struct tuple_printer<1, T...>{
    static void print(std::ostream& os, const std::tuple<T...>& t){
        //no need for comma separator
        os << std::get<0>(t);
    }
};

template <typename... T>
std::ostream& operator<<(std::ostream& os, const std::tuple<T...>& t)
{
    os << "[";
    tuple_printer<sizeof...(T), std::tuple<T...>>::print(os, t);
    return os << "]";
}

int main()
{
    std::cout << std::make_tuple(2, 3.14159F, 2345.678) << std::endl;
    std::cout << std::make_tuple("hello", 5) << std::endl;
    std::cout << std::make_tuple() << std::endl;
    return 0;
}

2 个答案:

答案 0 :(得分:2)

1. tuple_printer不会size_t, tuple<T...>而是size_t, T...

tuple_printer<s-1, std::tuple<T...>>替换为:

tuple_printer<s-1, T...>

tuple_printer<sizeof...(T), std::tuple<T...>>

tuple_printer<sizeof...(T), T...>

2.此外,您希望基本模板中的语句顺序与我猜有点不同:

tuple_printer<s-1, T...>::print(os, t);
os << ", ";
os << std::get<s-1>(t);

答案 1 :(得分:1)

std::cout << std::make_tuple(2, 3.14159F, 2345.678)

这会调用std::ostream& operator<< <int, float, double>(std::ostream& os, const std::tuple<int, float, double>& t)

从内部调用tuple_printer<sizeof...(T), std::tuple<T...>>::print(os, t);

void tuple_printer<3, std::tuple<int, float, double>>::print(
    std::ostream& os,
    const std::tuple<std::tuple<int, float, double>>& t);

注意加倍tuple。您明确地将tuple作为单个参数传递给T...,然后该函数将其包装在另一个元组中。

在此print功能中,您可以调用

std::get<2>(t)

无法编译,因为t只有一个元素。

在其他情况下,get<s-1>(t)成功,但返回一个元组,而不是一个基本元素,因此您尝试将其传递给operator<<,但是operator<<元组尚未被传递声明。