次の最小限の例を見てください。
_using Type1 = std::function<void(void)>;
template <typename T>
using Type2 = std::function<void(T)>;
Type1 whyDoesThisWork;
Type2<void> andYetThisDoesNot;
_
2番目のタイプエイリアスの場合、「引数に 'void'タイプがない可能性があります」というエラーが表示されます。 (Xcode 4.5、Clang/c ++ 11/libc ++、OS X 10.7でテストしました。)
私はこれが不思議だと思います:_Type1
_と_Type2<void>
_が同じように動作することを期待していました。何が起きてる?そして、2番目のタイプのエイリアスを書き換える方法がありますので、私はcan_Type2<void>
_を書き込み、代わりにstd::function<void(void)>
を取得しますエラー?
編集おそらくこれを追加したい理由は、次のようなことを許可するためです。
_template <typename ... T>
using Continuation = std::function<void(T...)>;
auto someFunc = []() -> void {
printf("I'm returning void!\n");
};
Continuation<decltype(someFunc())> c;
_
Continuation<decltype(someFunc())>
は_Continuation<void>
_になり、エラーが発生します。
短い答えは「テンプレートは文字列置換ではない」です。 void f(void)
は、Cとの下位互換性を保つために、C++でのvoid f()
のエイリアスである場合にのみ意味があります。
他の場所で述べたように、最初のステップは変分法を使用することです。
2番目のステップは、void
を返す関数を...にマップする方法を理解することです。まあ、std::function<void()>
のようなものか、別の何かかもしれません。他の場合とは異なり、std::function<void()> foo; foo( []()->void {} );
を呼び出すことができないため、他のことを言っているかもしれません。これは、真の継続ではありません。
このようなものは多分:
template<typename T>
struct Continuation
{
typedef std::function<void(T)> type;
};
template<>
struct Continuation<void>
{
typedef std::function<void()> type;
};
次に、次のように使用します。
auto someFunc = []()->void {};
Continuation<decltype(someFunc())>::type c;
これにより、必要なタイプが得られます。継続への適用を追加することもできます。
template<typename T>
struct Continuation
{
typedef std::function<void(T)> type;
template<typename func, typename... Args>
static void Apply( type const& cont, func&& f, Args... args)
{
cont( f(args...) );
}
};
template<>
struct Continuation<void>
{
typedef std::function<void()> type;
template<typename func, typename... Args>
static void Apply( type const& cont, func&& f, Args... args)
{
f(args...);
cont();
}
};
これにより、入力型がvoid型または非void型の場合、関数の実行に継続を均一に適用できます。
しかし、「なぜあなたはこれをしたいのですか?」
実際の答えはありません。コメントで言ったことだけです。次のように、関数の型としてvoid
を含めることはできません。
_int foo(int, char, void, bool, void, void); // nonsense!
_
T(void)
はCの互換性表記としてのみ許可されていると思います(これはdeclarationsとprototypesを区別し、C++とは非常に異なります)。 「引数なし」と言うことができます)。
したがって、ソリューションは可変的でなければなりません:
_template <typename ...Args> using myType = std::function<void(Args...)>;
_
そうすれば引数なしを正しく持つことができます:
_myType<> f = []() { std::cout << "Boo\n"; }
_
いくつかの回答がすでにその理論的根拠を説明しています。これらの答えに追加するために、仕様には(C++ 11§8.3.5[dcl.func]/4)と記載されています。
非依存型
void
の単一の名前のないパラメーターで構成されるパラメーターリストは、空のパラメーターリストと同等です。この特別な場合を除いて、パラメーターの型はcvvoid
であってはなりません。
_Type2
_の例では、void(T)
のT
は依存型-であり、テンプレートパラメータに依存します。
std::function<void(void)>
のように、関数がvoid
タイプのパラメーターを取るように宣言されている場合、これは実際には、パラメーターがゼロであることを示す間抜けな方法です。しかし、Type2を宣言した方法は、std::function
は何も返さない(void)が、1つのパラメーターをとるシグニチャーを使用します。 voidはパラメーターとして使用できる型ではなく、パラメーターがないことを宣言するための単なる方法です。したがって、Type2では機能しません。パラメーターとして使用できる実際の型が必要だからです。
関数に渡すと、Voidは空のパラメーターとして解釈されます。結局のところ、voidポインターを使用していません
void func (void)
なる
void func ()