2017-04-08 14 views
0

テンプレートの部分的な特殊化が不可視になる理由を理解しようとしています。C++ 14テンプレートの部分的な特殊化が表示されない

私は以下のエラーにどのように到達したかの小さな例を行っています。 この例では、ostreamsに出力するためにoperator<<をオーバーロードしようとしています。 タプルの印刷には1という質問で機能するソリューションがあります。私の質問は、以下のものが目に見えないエラーで失敗する理由です。

打ち鳴らすからの完全なエラー:

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; 
} 
+0

あなたの質問に関連していないが、私は 'テンプレート のstd :: ostreamに&演算子<<(STD :: ostreamに&OS、constのSTDあなたが知っていると仮定:::eは異なる私は推測しますtuple &t) 'は悪い計画ですか? – Yakk

+0

@ Yakk私はこのコードをデバッガのヘルパーとして使用しています。だから、私は、ソリューションを超汎用的にするための細部までは行かなかった。たとえば、弁護士の事例は考えていませんでした。しかし、私はあなたがそれについて特に懸念していることに興味があります。私はこのことから何かを学ぶつもりであると感じている:) – dvicino

+0

[なぜこれがうまくいかないのか](http://coliru.stacked-crooked.com/a/7ea7fd8f91a9958e) – Yakk

答えて

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に注意してください。 1つの引数としてtupleを明示的にT...に渡すと、その関数は別のタプルにその関数をラップします。

はこのprint機能内では、tが一つだけの要素を持っているので、コンパイルに失敗し

std::get<2>(t) 

を呼び出します。他のコンテキストで

get<s-1>(t)は成功しますが、あなたはその後、 operator<<にそれを渡すことを試みるので、タプルではなく、基本的な要素を返しますが、タプルについて operator<<はまだ宣言されていません。

2

  1. tuple_printersize_t, tuple<T...>が、size_t, T...を負いません。また、あなたがしたいと思います

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

  2:と

tuple_printer<s-1, T...> 

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

が持つtuple_printer<s-1, std::tuple<T...>>を交換してください基本テンプレート内の文の順序をlittlにする

tuple_printer<s-1, T...>::print(os, t); 
os << ", "; 
os << std::get<s-1>(t); 
関連する問題