私はいくつかの異なる機能を共有するクラスを書いていますstd::function
(または少なくともクラスは多くの点で似ています)。std::function
はテンプレート パラメーター (つまり ) を指定することでインスタンス化されることはご存知のとおりstd::function<void (std::string&)>
、私のクラスでも同じです。ただし、例外があります。戻り値が void ( ) の場合、クラスで単一の関数を特殊化したいと考えていますstd::function<"return value" ("parameters">
。コンパイル時にこれを行う必要がありますが、本来の動作をさせることができません。説明のためのテストコードを次に示します。
#include <iostream>
#include <type_traits>
template <typename T> class Test { };
template <typename Ret, typename... Args>
class Test<Ret (Args...)>
{
public:
Ret operator()(Args...)
{
if(std::is_void<Ret>::value)
{
// Do something...
}
else /* Not a void function */
{
Ret returnVal;
return returnVal;
}
}
};
int main(int argc, char * argv[])
{
Test<void (char)> test;
test('k');
}
ご覧のとおり、上記のテストでコンパイラが「else」ブランチを削除しない場合、私のコードは void 値 (つまりvoid returnVal;
) を作成しようとします。問題は、コンパイラがブランチを削除しないため、コンパイラ エラーが発生することです。
./test.cpp: 'Ret Test::operator()(Args ...) [with Ret = void; のインスタンス化中。Args = {char}]': ./test.cpp:27:10: ここから必要 ./test.cpp:18:8: エラー: 変数またはフィールド 'returnVal' は void を宣言しました ./test.cpp:19:11 : エラー: 'void' を返す関数の値を含む return-statement [-fpermissive]
通常はstd::enable_if
と組み合わせて使用しますが、問題は、関数テンプレートではなく、クラスstd::is_void
テンプレートに特化したいということです。
template <typename Ret, typename... Args>
class Test<Ret (Args...)>
{
public:
typename std::enable_if<!std::is_void<Ret>::value, Ret>::type
Ret operator()(Args...)
{
Ret returnVal;
return returnVal;
}
typename std::enable_if<std::is_void<Ret>::value, Ret>::type
Ret operator()(Args...)
{
// It's a void function
// ...
}
};
代わりに上記のコードを使用すると、さらに多くのエラーが発生し、解決策がありません
./test.cpp:11:2: error: expected ‘;’ at end of member declaration
./test.cpp:11:2: error: declaration of ‘typename std::enable_if<(! std::is_void<_Tp>::value), Ret>::type Test<Ret(Args ...)>::Ret’
./test.cpp:6:11: error: shadows template parm ‘class Ret’
./test.cpp:11:24: error: ISO C++ forbids declaration of ‘operator()’ with no type [-fpermissive]
./test.cpp:18:2: error: expected ‘;’ at end of member declaration
./test.cpp:18:2: error: declaration of ‘typename std::enable_if<std::is_void<_Tp>::value, Ret>::type Test<Ret(Args ...)>::Ret’
./test.cpp:6:11: error: shadows template parm ‘class Ret’
./test.cpp:18:24: error: ISO C++ forbids declaration of ‘operator()’ with no type [-fpermissive]
./test.cpp:18:6: error: ‘int Test<Ret(Args ...)>::operator()(Args ...)’ cannot be overloaded
./test.cpp:11:6: error: with ‘int Test<Ret(Args ...)>::operator()(Args ...)’
./test.cpp: In member function ‘int Test<Ret(Args ...)>::operator()(Args ...)’:
./test.cpp:22:2: warning: no return statement in function returning non-void [-Wreturn-type]
./test.cpp: In instantiation of ‘int Test<Ret(Args ...)>::operator()(Args ...) [with Ret = void; Args = {char}]’:
./test.cpp:28:10: required from here
./test.cpp:13:7: error: variable or field ‘returnVal’ declared void
./test.cpp: In member function ‘int Test<Ret(Args ...)>::operator()(Args ...) [with Ret = void; Args = {char}]’:
./test.cpp:15:2: warning: control reaches end of non-void function [-Wreturn-type]
私がただのばかで申し訳ありませんが、答えは明らかです。私はテンプレートにかなり慣れていないので、他のスレッド/質問で適切な答えを見つけることができませんでした.