2017-06-29 17 views
1

私の関数は、与えられた入力引数(variadic)のセットを持つPython関数を呼び出し、関数の出力を含むタプルを返します。C++バリデーションテンプレート戻り型

私はMinGW-w64コンパイラのg ++​​ポート(C++ 11)を使用してWindows 10マシンでコンパイルしています。次のように私は(とそれを呼び出す)このテンプレート可変引数の関数を宣言した:

// Declaration (in PyInterface.h) 
template <typename... Inputs, typename... Outputs> 
const std::tuple<Outputs...>& callFunction(const std::string &modulePath, const std::string &funcName, Inputs&&... args) { 
    // Calls a Python function & packs output variables into a std::tuple... 
} 

// Sample call (in main.cpp) 
const std::tuple<std::string, std::string> output = pi.callFunction(myModulePath, myFuncName, inputArg1, inputArg2, inputArg3); 

しかし、このエラーがスローされます(読みやすくするための...に短縮):

conversion from 'const std::tuple<>' to non-scalar type 'const std::tuple<std::__cxx11::basic_string<...>, std::__cxx11::basic_string<...> >' requested

を私の知る限りとして私はusing two variadic templates is legalを認識しています。さらに、戻り値の型は変数(const std::tuple<std::string, std::string> output)によって明示的に設定されているようですが、関数の結果を代入しようとしているので、コンパイラは 型の戻り値を知っている必要があります。

元々、私はエラーが単に私がvariadicテンプレートを適切に使用していないことを示していたと思いました。戻り値の型(const T<Outputs...>& callFunction)を指定するために、ネストされたテンプレートパラメータ(here)を使用してみました。ただし、テンプレートの控除がTで失敗したことを示すエラーメッセージが表示されただけです。

このエラーは、私の直感が間違っていて、元の関数では、コンパイラがoutputの型から目的の戻り値の型を推測していないことを示します。

なぜ私の直感は間違っていますか?どのように私は正しくvariadicテンプレートを使用してこの関数の戻り値の型を指定しますか?

+1

'Outputs'の型を指定することはありません。 – NathanOliver

+0

@ NathanOliver 'Outputs'の型をどのように指定すればよいか教えてください。 'pi.callFunction 'の呼び出しを修正しようとしましたが、エラーメッセージの意味を理解できませんでした: 'error:can not bind 'const string {別名const std :: __ cxx11 :: basic_string }' lvalue to 'std :: __ cxx11 :: basic_string &&' ' –

+0

Input型として明示的に 'string'を指定しています。右辺値参照は関数引数宣言 'Inputs &&'と組み合わされて得られます。 'const string'の左辺値を渡しています。これは、使用する前に少なくとも' const'を削除する必要があります。 Input型が暗黙的に拾われたところの答えのほかに、 'Inputs &&'と組み合わされたときに' const string& 'のままであるInput型として' const string& 'を明示的に指定できます。 –

答えて

1

戻り値の型を関数のスコープ内にある返されるオブジェクトの型に基づいて推測する場合は、C++ 14の場合は戻り値の型としてautoを使用できます。それは魔法のように動作

template <typename... Inputs> 
const auto& callFunction(
    const std::string &modulePath, 
    const std::string &funcName, 
    Inputs&&... args) { 

    return object; 
} 

いつものようにあなたは、この関数からconst参照を返していることに注意してください。

あなたはC++ 11、あなたが例decltype(obj)はあなたが返すようにしたいものの一種で

template <typename T> 
auto identity_return(T& obj) -> decltype(obj) { 
    return obj; 
} 

ため、末尾の戻り値の型を使用することができますを使用している場合。この場合もやはり参考になります。

一般的に、関数から値を取得しようとしても、返されたものが返り値よりも長生きするかどうかわからない場合は、参照を返すと参照が壊れる可能性があります。


別の解決策は、単に手動でOutputs...タイプのリストを指定すると、コンパイラは、C++コンパイラのエラーメッセージでタイプいつものようにInputs...

template <typename... Outputs, typename... Inputs> 
const std::tuple<Outputs...>& callFunction(
    const std::string &modulePath, 
    const std::string &funcName, 
    Inputs&&... args) { ... } 

auto tup = callFunction<std::string, std::string>(modulePath, funcName, args); 
+0

破壊されたローカルオブジェクトへの参照を返しています。 – NathanOliver

+0

@ NathanOliverだから、私は最後に「注意してください」ということを言いました! – Curious

+0

私は何を伝えようとしているのかというと、あなたが "正しい方法"を行うことができ、あなたがそうした理由を説明するときにあなたの例で悪いコードを使用するのです。 – NathanOliver

0

を推定させることです、最初のものはあなたが必要とする唯一のものですを見て。私はあなたがtuple値を作成していることを推測しています(コードを提供していないため)。そして、const参照を返します。関数の最後にはtupleが破壊されているので、参照は何を参照するべきですか?tuple<Outputs...>を返すだけです。

InputOutputタイプパックを交換することで、あなたが望むものを実現できると思います。また、このコードは、show機能を持つInputsタイプパックの繰り返しを示しています。同様のことをして、PythonタプルオブジェクトとOutputsタイプパックからtuple<Outputs...>値を構築することもできます。

#include <iostream> 
#include <tuple> 
#include <utility> 

using namespace std; 

template< typename Output > struct convert_t; 
template<> struct convert_t<string> 
{ 
    string operator()(const char *text) const 
    { 
     return text; 
    } 

    string operator()(double val) const 
    { 
     return to_string(val); 
    } 
}; 

inline void show() 
{} 

template< typename First, typename... Others > 
inline void show(First &&first, Others&&... others) 
{ 
    cout << first << "\n"; 
    show(forward<Others>(others)...); 
} 

template< typename... Outputs, typename... Inputs > 
inline tuple<Outputs...> funkyfunc(Inputs&&... inputs) 
{ 
    cout << "Inputs...\n"; 
    show(forward<Inputs>(inputs)...); 
    return tuple<Outputs...>(convert_t<Outputs>()(inputs)...); 
} 

int main() 
{ 
    auto t = funkyfunc< string, string >("text", 123.0); 
    cout << "Outputs...\n"; 
    cout << get<0>(t) << "\n"; 
    cout << get<1>(t) << "\n"; 

    return 0; 
} 
関連する問題