27

次の最小限の例を見てください。

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 番目の型エイリアスを書き直す方法はありますか?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>、エラーが発生します。

4

5 に答える 5

15

実際の答えはありません。コメントで言ったことだけです。次のようにvoid、関数型として持つことはできません。

int foo(int, char, void, bool, void, void);     // nonsense!

T(void)これは、C の互換表記としてのみ許可されていると思います(C++ とは大きく異なり、宣言プロトタイプを区別し、「引数なし」と言える必要があります)。

したがって、ソリューションは可変長でなければなりません。

template <typename ...Args> using myType = std::function<void(Args...)>;

そうすれば、適切に引数を持たないことができます:

myType<> f = []() { std::cout << "Boo\n"; }
于 2012-11-14T02:41:10.557 に答える
14

短い答えは、「テンプレートは文字列置換ではありません」です。 C との下位互換性を維持するために、C++void f(void)のエイリアスである場合にのみ意味があります。void f()

最初のステップは、他の場所で説明されているように、変数を使用することです。

void2 番目のステップは、返される関数を ...にマップする方法を考え出す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;

これにより、必要なタイプが得られます。apply to continuation を追加することもできます:

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 型の場合に、関数の実行に均一に継続を適用できます。

しかし、「なぜこれをやりたいのか」と尋ねます。

于 2012-11-14T03:56:22.017 に答える
8

いくつかの回答がすでにその根拠を説明しています。これらの回答に追加するために、仕様には次のように記載されています (C++11 §8.3.5[dcl.func]/4):

非依存型の単一の名前のないパラメーターで構成されるパラメーター リストvoidは、空のパラメーター リストと同等です。この特殊なケースを除いて、パラメータはcv void型を持たないものとします。

あなたのType2例では、Tinvoid(T)依存型です-それはテンプレートパラメーターに依存します。

于 2012-11-14T04:12:51.493 に答える
3

のように、関数が type のパラメータを取るように宣言されている場合voidstd::function<void(void)>それは実際にはパラメータがゼロであると言う間抜けな言い方です。しかし、Type2 を宣言した方法は、std::function何も返さない (void) シグネチャを持つものですが、1 つのパラメーターを取ります。void はパラメーターとして使用できる型ではなく、パラメーターがないことを宣言する方法にすぎません。したがって、Type2 ではパラメーターとして使用できる実際の型が必要なため、これは機能しません。

于 2012-11-14T02:36:01.613 に答える
0

Void を関数に渡すと、空のパラメーターとして解釈される場合があります。結局のところ、void ポインターを使用していないので、

void func (void)

になる

void func ()
于 2012-11-14T02:37:05.810 に答える