2017-01-13 5 views
1

このコードを動作させようとしましたが、解決策を見つけようとしました。私は戻り値の型をオーバーロードすることはできませんが、それを解決する方法はわかりません。テンプレート関数から複数の値をstd :: tupleとして返します。

このエラーは発生していますが、どこからstd :: basic_string以外の参照を取得するのかわかりません。 error C2440: 'return': cannot convert from 'std::tuple<std::basic_string<char,std::char_traits<char>,std::allocator<char>>,int &,float &>' to 'std::tuple<std::string &,int &,float &>'

#include <functional> 
#include <iostream> 
#include <string> 
#include <tuple> 

template <typename T> 
T Get(); 

template <> 
std::string Get() { return std::string{ "Hello" }; } 

template <> 
int Get(){ return 42; } 

template <> 
float Get() { return 42.0; } 

template <typename T> 
std::tuple<T> Generate() 
{ 
    return std::make_tuple(Get<T>()); 
} 

template <typename T1, typename... Ts> 
std::tuple<T1,Ts...> Generate() 
{ 
    auto t = std::make_tuple(Get<T1>()); 
    return std::tuple_cat(t, Generate<Ts...>()); 
} 

struct A 
{ 
    template <typename... Ts > 
    operator std::tuple<Ts...>() 
    { 
     return Generate<Ts...>(); 
    } 
}; 

int main() 
{ 
    std::string s; 
    int i; 
    float f; 
    A as; 
    std::tie(s, i, f) = as; 
} 

答えて

1
std::tie(s, i, f) = as; 

左側がtuple<string&,int&,float&>なので、右側は同じものに変換しようとします。これらの参照に注意してください。このためにはGenerateが一致する型を返す必要があります。だからmake_tupleは行く必要があります、それはtieでなければなりません。しかし、あなたのGet関数も参照を返す必要があります。できる。私はその間に、Generateコールを再帰的ではないように単純化しました。実行の

template <typename T> 
T Get(); 

//note references, and a static variable, and explicitly saying T 
template <> 
std::string& Get<std::string&>() { static std::string a{ "Hello" }; return a;} 

template <> 
int& Get<int&>(){ static int a{42}; return a; } 

template <> 
float& Get<float&>() { static float a{42.0f}; return a; } 

// note tie and non-recursive 
template <typename ...T> 
std::tuple<T...> Generate() 
{ 
    return std::tie(Get<T>()...); 
} 

struct A 
{ 
    template <typename... Ts > 
    operator std::tuple<Ts...>() 
    { 
     return Generate<Ts...>(); 
    } 
}; 

int main() 
{ 
    std::string s; 
    int i; 
    float f; 
    A as; 
    std::tie(s, i, f) = as; 
    std::cout << "pass"; 
} 

証明:SU3ノートとしてhttp://coliru.stacked-crooked.com/a/036817509172da69

Generateは冗長です。私は元の質問に含めることができなかった第二の問題を持っていたように私自身の答えを追加

struct A 
{ 
    template <typename... Ts > 
    operator std::tuple<Ts...>() 
    { 
     return std::tie(Get<T>()...); 
    } 
}; 
+0

+1戻り値が割り当てられているオブジェクトのタイプに基づいて、関数テンプレートのパラメータを推測できることはわかりませんでした。 – SU3

+0

@ SU3:それはかなり秘話です。テンプレート演算子T() 'のみで動作し、完全一致(参照とconstを除く)のみ行います。また、どのタイプにも割り当てることができるため、いくつかのエラーメッセージが表示されます。 –

+0

ありがとう..これは質問に答えますが、実際にはget関数に渡すためのインデックスが必要なので、私は再帰を必要とします。このテストケースではなく、私が実際に使っているコードでこれを行う方法はありますか? – TLoe

0

これはいかがですか?

#include <iostream> 
#include <string> 
#include <tuple> 

template <typename T> 
T Get(); 

template <> 
std::string Get<std::string>() { return "Hello"; } 

template <> 
int Get<int>(){ return 42; } 

template <> 
float Get<float>() { return 42.0; } 

template <typename... Args> 
std::tuple<Args...> Generate() { 
    return { Get<Args>()... }; 
} 

int main() 
{ 
    std::string s; 
    int i; 
    float f; 
    std::tie(s, i, f) = Generate<std::string,int,float>(); 

    std::cout << s << std::endl; 
    std::cout << i << std::endl; 
    std::cout << f << std::endl; 
} 

戻り値の型を指定するだけでは、関数テンプレートを特殊化することはできません。代わりに、テンプレートパラメータを明示的に指定する必要があります。

また、std::tupleを使用すると、C++ 11以上を使用していることを意味します。したがって、再帰の代わりにパラメータパックを使用できます。これは単なる構文的な砂糖ですが、それはただ1つのGenerate()関数の実装を書くことができます。

0

だったかもしれません。私はGet関数に渡されたインデックスが必要でしたので、このインデックスを使用して、別の投稿で見つけたトリックを作成しました。

#include <functional> 
#include <iostream> 
#include <string> 
#include <tuple> 


template <std::size_t... Is> 
struct Indices {}; 

template <std::size_t N, std::size_t... Is> 
struct IndicesBuilder : IndicesBuilder<N - 1, N - 1, Is...> 
{}; 

template <std::size_t... Is> 
struct IndicesBuilder<0, Is...> 
{ 
    using type = Indices<Is...>; 
}; 

template <typename T> 
T& Get(int index); 

template <> 
std::string& Get<std::string&>(int index) { std::cout << index << std::endl; static std::string s{ "Hello" }; return s; } 

template <> 
int& Get<int&>(int index) { std::cout << index << std::endl; static int i{ 42 }; return i; } 

template <> 
float& Get<float&>(int index) { std::cout << index << std::endl; static float f{ 42 }; return f; } 

template <typename... Ts, std::size_t... N> 
std::tuple<Ts...> Generate(Indices<N...>) 
{ 
    return std::tie(Get<Ts>(N)...); 
} 

struct A 
{ 
    template <typename... Ts > 
    operator std::tuple<Ts...>() 
    { 
     constexpr std::size_t count = sizeof...(Ts); 

     return Generate<Ts...>(typename IndicesBuilder<count>::type()); 
    } 
}; 

int main() 
{ 
    std::string s; 
    int i; 
    float f; 
    A as; 
    std::tie(s, i, f) = as; 
    std::cout << s << " " << i << " " << f << std::endl; 
} 
関連する問題