2016-08-27 8 views
2

私はC++のテンプレートについて学んでいたので、私はそれらを動作させることができるかどうかを確認するために、いくつか異常な状況に遭遇することにしました。 (いいえ、それは実用的ではありません - ただ言語を使って遊ぶことです)タイプTの値を保持するテンプレートクラスを作成し、std::pairTに返し、パラメータの値のうち最大値の1つを返すバリデーション関数テンプレートを使用しましたパック。しかし、私はそれをコンパイルすることはできません。 source.cpp非可変テンプレートクラス内に可変テンプレート関数を作成するにはどうすればよいですか?

#ifndef HEADER_H 
#define HEADER_H 

#include <utility> 
#include <algorithm> 
#include <array> 

template <typename T> 
class MyClass 
{ 

    T m_heldType; 

public: 

    MyClass(T t) : m_heldType(t) {} 

    template <typename... T2> 
    std::pair<T, T2> pairingFunc(T2&&... types) 
    { 
    std::array<T2, sizeof...(types)> types_arr = { types... }; 

    return std::make_pair(m_heldType, *std::max_element(types_arr.begin(), types_arr.end())); 
    } 

}; 

#endif 

:ここ

がheader.hで...私が書いたものだ

#include <iostream> 
#include "Header.h" 

int main() 
{ 
    MyClass<int> mc(512); 

    auto mypair = mc.pairingFunc(1.61f, 3.14f, 6.66f); 

    std::cout << mypair.first << ' ' << mypair.second; 
    std::cin.ignore(); 
} 

これらは私が生成するエラーです。

Error C3520 'T2': parameter pack must be expanded in this context ...\header.h 24 
Error C2672 'MyClass<int>::pairingFunc': no matching overloaded function found ...\source.cpp 8 
Error C2893 Failed to specialize function template 'std::pair<T,T2> MyClass<T>::pairingFunc(T2 &&...)' ...\source.cpp 8 
Error C3536 'mypair': cannot be used before it is initialized ...\source.cpp 10 
Error C2228 left of '.first' must have class/struct/union ...\source.cpp 10 
Error C2228 left of '.second' must have class/struct/union ...\source.cpp 10 

だから、ここで私が考えているものです:

  • は明らかに、コンパイラはmypairの種類を判別することはできません(初期化に失敗)。しかし、なぜ? TのタイプはMyClassT2のタイプはpairingFunc()です。明示的にstd::pair<int, float>と記載するとこのエラーは修正されますが、他のもの(根本的な問題の症状)は残ります。
  • "関数テンプレートを特殊化できませんでした" ...指定した型に基づいて型を返すことができなかったと思いますか?もしそうなら、どうしてですか?
  • "このコンテキストではパラメータパックを展開する必要があります" - これについてはわかりません。パックを配列に入れてもそれは起こりませんか?

また、私が(T2&& head, T2&&... tail)のようなものを介して、少なくとも1つの引数の提供を強化したいと思いますが、私は、配列またはベクターにそれらの両方を得ることは厄介なことができると思いますし、私が対処するかどうかはわかりませんそれはただ一つのバリデーショナルである。それはちょうど私が推測する「ボーナス」です。

答えて

2

問題はここにある:提案std::common_type_tは良い選択です。複数のタイプ(例:1.4f, "hi", 1, 0.5)を保存できます。だからあなたはそれを単一のタイプとして使うことはできません。ただ可能ではありません。

template <typename T1, typename... T2> 
std::pair<T, T1> pairingFunc(T1&& arg, T2&&... types) 
{ 
    std::array<T1, sizeof...(types) + 1> types_arr = { arg, types... }; 

    return std::make_pair(m_heldType, *std::max_element(types_arr.begin(), types_arr.end())); 
} 

これはまた、あなたが

mc.pairingFunc(4.5f, "hello"); 

を呼び出す場合、それがコンパイルされないだろうという利点があります:あなたは別のパラメータを導入し、タイプとしてことを使用する必要があります。引数なしでそれを呼び出すことはもはや不可能である(これはそれにもかかわらず)。


好ましい溶液(おかげ@DanielSchepler)は、2番目の引数はTに変換されないが、Tが二番目の引数に変換可能であることが可能であるように、std::common_typeを使用するかもしれない:

template <typename T1, typename... T2> 
std::pair<T, std::common_type_t<T1, T2...>> pairingFunc(T1&& arg, T2&&... types) 
{ 
    std::array<std::common_type_t<T1, T2...>, sizeof...(types) + 1> types_arr = { arg, types... }; 

    return std::make_pair(m_heldType, *std::max_element(types_arr.begin(), types_arr.end())); 
} 
+2

また、配列の型に 'std :: common_type_t 'を、戻り型の2番目のメンバを使用するのが適切かもしれません。 –

+0

@DanielSchepler良いアイデアは、 'std :: common_type'、感謝について知りませんでした: – Rakete1111

+0

@ Rakete1111あなたの答えをありがとう!私は、「T2」を参照すると、単に「T2の型の配列」を意味し、パラメータパック全体ではないと仮定しました。それは私が(頭、尾...)考えに近づいていたことを意味します。加えて、「少なくとも1つのargを持つ必要があります」という制限と1回のタイピングが追加されています。再度、ありがとう、これは明確で、ポイントの答えでした。 –

2

根本的な問題は、パラメータパック

<typename ...T2> 

は、単一の種類を表していないということです。このパラメータパックは種類の組み合わせを受け入れることができ

template <typename... T2> 
void foo(T2 && ...args) 

、すなわち

foo(4, "bar", Baz()); 

あなたはpairingFunc()が受け取るパラメータの種類を把握する必要があります。パラメータパック、ないタイプここ

std::pair<T, T2> pairingFunc(T2&&... types) 
      ^^ 

std::array<T2, sizeof...(types)> types_arr = { types... }; 
      ^^ 

T2さ:

template <typename T> 
class MyClass 
{ 

    T m_heldType; 

public: 

    MyClass(T t) : m_heldType(t) {} 

    template <typename ...T2> 
    auto pairingFunc(T2 &&...values) 
    { 
     std::array<std::common_type_t<T2...>, sizeof...(T2)> types_arr = { values... }; 

     return std::make_pair(m_heldType, *std::max_element(types_arr.begin(), types_arr.end())); 
    } 

}; 
+0

ありがとうございます。この回答も良いですが、少なくとも1つの引数を必要とするメソッドシグネチャを使用し、 'std :: common_type'を使用しないでもう一方を受け入れています。しかし、今私はそれについて知っているので、私はそれを私の兵器に加えることができます。 –

+1

'std :: common_type'を使わないと、値の型は最初のパラメータのものと強制的に一致します。私。内部の 'std :: array'は浮動小数点の代わりに' int'sを含むので、pairingFunc(0,1.2f、3.4f)はコンパイラ警告を生成します。 –

+0

したがって、 'std :: common type'は次の型の暗黙の変換も考慮していますか?文脈(リテラルを使って作業すれば、明示的に 'f'や' l'などと言いたい)に依存して多かれ少なかれ望ましいかもしれないが、やはり便利だ。 –

関連する問題