1

テンプレートパラメーターを継承し、特定の基本メンバー関数のすべてのオーバーロードを一度にオーバーライドするテンプレートラッパークラスを作成しようとしています。次に例を示します。

#include <cassert>
#include <string>   
#include <utility>

template <class T>
class Wrapper: public T {
public:
  template <typename... Args>
  Wrapper<T>& operator=(Args&&... args) {
    return this_member_fn(&T::operator=, std::forward<Args>(args)...);
  }

private:
  template <typename... Args>
  Wrapper<T>& this_member_fn(T& (T::*func)(Args...), Args&&... args) {
    (this->*func)(std::forward<Args>(args)...);
    return *this;
  }   
};

int main(int, char**) {
  Wrapper<std::string> w;
  const std::string s("!!!");
  w = s;
  assert(w == s);
  w = std::string("???");
  assert(w == std::string("???"));
  return 0;
}

のテンプレートはWrapper<T>::operator=、コンパイル時に引数に基づいて正しいT :: operator =を選択し、それらの引数をに転送するという考え方です。で構築する場合

gcc -std=c++11 -W -Wall -Wextra -pedantic test.cpp -lstdc++

gccから次の苦情があります。

test.cpp: In instantiation of ‘Wrapper<T>& Wrapper<T>::operator=(Args&& ...) [with Args = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >}; T = std::basic_string<char>]’:
test.cpp:26:24:   required from here
test.cpp:10:69: error: no matching function for call to ‘Wrapper<std::basic_string<char> >::this_member_fn(<unresolved overloaded function type>, std::basic_string<char>)’
test.cpp:10:69: note: candidate is:
test.cpp:15:15: note: Wrapper<T>& Wrapper<T>::this_member_fn(T& (T::*)(Args ...), Args&& ...) [with Args = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >}; T = std::basic_string<char>]
test.cpp:15:15: note:   no known conversion for argument 1 from ‘&lt;unresolved overloaded function type>’ to ‘std::basic_string<char>& (std::basic_string<char>::*)(std::basic_string<char>)’
test.cpp: In member function ‘Wrapper<T>& Wrapper<T>::operator=(Args&& ...) [with Args = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >}; T = std::basic_string<char>]’:
test.cpp:11:3: warning: control reaches end of non-void function [-Wreturn-type]

26w = std::string("???");行目はthis_member_fnの宣言であり、15行目はthis_member_fnの宣言であるため、コンパイラーが考えるタイプfunc(= std::string::operator=)は期待していたタイプではないようです。

基本クラスのそれぞれを個別にoperator=オーバーライドするのではなく、私と同じようにテンプレートを使用してこれを行う方法はありますか?operator=

4

3 に答える 3

4

その場で利用する場合は、会員の住所を聞く必要はありません。これにより、オーバーロードされたどのバージョンを選択するかを見つける問題も回避できます。

template<
    typename U
    , typename std::enable_if<
        std::is_assignable<T&, U>::value
        , int
    >::type = 0
>
Wrapper& operator=(U&& u)
{
    static_cast<T&>(*this) = std::forward<U>(u);
    return *this;
}

制約 ( を介した SFINAE テスト) を強くお勧めします。それ以外の場合は、をに代入しようstd::enable_ifとして失敗するような単純なものです。制約により、特別なメンバーが適切に選択されます。Wrapper<int> w, v; w = v;Wrapper<int>intWrapper& operator=(Wrapper const&);

于 2012-06-25T19:05:33.140 に答える
1

がいくつかstd::string::operator=あるため、式&T::operator=whereはメンバー function へのポインターにT = std::stringはなりません。

于 2012-06-25T18:50:19.927 に答える
1

いいえ、関数テンプレートを virtualにすることはできないため、何もオーバーライドできません。

ただし、非仮想関数テンプレートを使用して (何もオーバーライドしないように)、名前を明示的に修飾することで基本クラス関数を呼び出すことができます。

this->T::operator=(std::forward<Args>(args)...);
return *this;

(this->は実際には不要ですが、わかりやすくするために含まれています。)

これにより、オーバーロードの解決によって適切な関数が選択されますが、バージョンで&T::operator=は単一のオーバーロードに明確に名前が付けられていないため、単一の関数のアドレスではありません (T::operator=オーバーロード セット全体に名前を付け、オーバーロード セットは C++ のファーストクラス オブジェクトではありません)。そのため、関数に渡すことはできません。)

基本クラスの代入演算子が正しい型を返さないため、その式を返すことはできません。a を使用することもできますが、static_cast<Wrapper&>(...)単に返す方が簡単です*this

于 2012-06-25T18:50:51.160 に答える