3

他の関数を呼び出すテンプレート関数に const ref パラメータを渡す際に問題があります。次のコードを検討してください。

struct A
{
    void foo(const int& i) { }
};

template <class ...Args> 
void a_caller(A& a, void(A::*f)(Args...), Args&& ...args)
{
    (a.*f)(std::forward<Args>(args)...);
}

int main()
{
    int i = 42;
    A a;

    a_caller(a, &A::foo, i); // (1) compiler error
    a_caller<const int&>(a, &A::foo, i); // (2) ok
}

したがって、ラッパーで呼び出したい引数をA::foo持つメンバー関数があります。行 (1) により、次のエラーが発生します。const int&a_caller

'void a_caller(A &,void (__thiscall A::* )(Args...),Args &&...)' : template parameter 'Args' is ambiguous
see declaration of 'a_caller'
could be 'const int&'
or       'int&'

私の最初の質問は、なぜこれが起こるのですか?オーバーロードされていない関数 A::foo をコンパイラに与えますが、それから推論できないのはなぜArgsですか? 2 番目の質問は、なぜこれが std::make_unique で起こらないのかということです。次のコードは同じように見えますが、コンパイラーはコンストラクターの引数の型を問題なく推測します。

struct A
{
    A(const int& i)  { }
};

int main()
{
    int i = 42;
    auto aptr = std::make_unique<A>(i);
}
4

3 に答える 3

1

エラーメッセージは何が起こっているかを教えてくれます

see declaration of 'a_caller'
could be 'const int&'
or       'int&'

したがって、 を受け取るメンバー関数を渡しているconst int&ため、コンパイラはそれをArgsとして推測しますが、として推測するメンバー関数const int&も渡します。これらは競合するため、エラーが発生します。コンパイルするか、2 番目のパラメーターとしてa を渡すことができます。iArgsint&const_cast iconst int

a_caller(a, &A::foo, const_cast<const int&>(i)); 
const int foo = 42;
a_caller(a, &A::foo, foo);
于 2015-08-17T12:42:43.603 に答える
1

私の最初の質問は、なぜこれが起こるのですか?オーバーロードされていない関数 A::foo をコンパイラに与えましたが、なぜそこから Args を推測できないのでしょうか?

関数 a_caller の最初と 2 番目のパラメーターに対して、Args を 2 回推定しようとするためです。const int&そして、この推定された型は、最初のパラメーターと2 番目のパラメーターで一致しませんint&

2 番目の質問は、なぜこれが std::make_unique で起こらないのかということです。

make_unique はその引数をクラス コンストラクターに転送するだけだからです。

あなたのコードは次のようになるはずです:

#include <memory>

struct A
{
    void foo(const int& i) { }
};

template <typename F, class ...Args> 
void a_caller(A& a, F &&f, Args&& ...args)
{
    (a.*f)(std::forward<Args>(args)...);
}

int main()
{
    int i = 42;
    A a;

    a_caller(a, &A::foo, i);
}

デモ

于 2015-08-17T12:58:41.147 に答える