1

派生クラスが設定する必要のあるフラグが内部にある基本クラスがあるとします。

struct Base
{
    bool flag;
    Base(bool flag):flag(flag) {}
};

trueデータ駆動型の方法でフラグを/に設定する派生クラスを構成しfalseたい-つまり、ヘッダーからこれを構成したい。

struct Derived1 : Base
{
    Derived1() : Base( expr ) {}
};

ヘッダーから情報を取得できるもの(まだ何がわからないか)はどこexprにありますか? trueかfalseかを教えてください。理想的には、新しい派生クラスを作成したが、ヘッダーでフラグを指定しなかった場合にエラーが発生しますが、これは必須ではありません。このようにして、1つの中央の場所を変更するだけで変更を加えることができます。Derived1flag

これに対する慣用的なアプローチは何ですか?

4

4 に答える 4

2

単一の関数を使用する代替バージョンは、よりコンパクトな場合があります。

struct Derived1 : Base
{
    Derived1() : Base(theFlag(this)) {}
};

次に、ヘッダーで:

template <typename T>
bool theFlag(T*)
{
   if (typeid(T) == typeid(Derived1)) return true;
   if (typeid(T) == typeid(Derived2)) return false;
   if (typeid(T) == typeid(Derived3)) return true;

   throw std::runtime_error("No theFlag is given for this type");
}

コンパイル時のチェックと結婚している場合、できる最善の方法は、少し重複を導入することです。

template <typename T>
bool theFlag(T*)
{
   static_assert(
      std::is_same<T, Derived1>::value ||
      std::is_same<T, Derived2>::value ||
      std::is_same<T, Derived3>::value,
      "No theFlag is given for this type"
   );

   if (typeid(T) == typeid(Derived1)) return true;
   if (typeid(T) == typeid(Derived2)) return false;
   if (typeid(T) == typeid(Derived3)) return true;
}

これは基本的にSFINAEに依存してtheFlagいます。基本的に、サポートされていない引数を使用して呼び出した場合、コンパイラはオーバーロードを見つけることができません。

于 2013-02-04T12:19:16.803 に答える
2

あなたは書くことができます:

struct Derived1 : Base
{
    Derived1() : Base(Concept<Derived1>::theFlag) {}
};

また、ヘッダーには次のものが含まれる可能性があります。

template <typename T>
struct Concept
{};

template <>
struct Concept<Derived1>
{
   static const bool theFlag = true;
};

タイプごとに特殊化が繰り返されます。

それはあなたが意味したことですか?一部にフラグ値を指定しなかった場合、コンパイルは失敗しますDerivedN

于 2013-02-04T12:15:25.273 に答える
2

フラグのトレイトクラスを作成し、マクロを使用して特殊化を定義します。

#include <type_traits>

template<typename T>
struct FlagTrait {
    static_assert(std::is_void<T>::value, "No flag defined for this type.");
};

#define DEFINE_FLAG(Type, Val)               \
        template<>                           \
        struct FlagTrait<class Type>         \
            : std::integral_constant<bool, Val> {};

template<typename T>
constexpr bool getFlag(T) { return FlagTrait<T>::value; }

#define GET_FLAG getFlag(*this)

これで、新しい派生クラスごとに行う必要があるのは、クラス名とフラグの値を含む行を追加することだけです。

DEFINE_FLAG(Derived1, true)
DEFINE_FLAG(Derived2, false)

使用法:

struct Base
{
    bool flag;
    Base(bool flag):flag(flag) {}
};

struct Derived1 : Base
{
    Derived1() : Base(GET_FLAG) {}
};

struct Derived2 : Base
{
     Derived2() : Base(GET_FLAG) {}
};
于 2013-02-04T13:49:51.583 に答える
1

純粋なコンパイル時のソリューションは次のとおりです。

struct Derived1 ;
struct Derived2 ;
template <typename Derived> struct Bootstrap
{
    bool init(Derived1 *) { return true ; }
    bool init(Derived2 *) { return false ; }
    Bootstrap():flag(init(static_cast<Derived *>(this))){}
    bool flag ;
};
struct Derived1: public Bootstrap <Derived1> {};
struct Derived2: public Bootstrap <Derived2> {};
int main()
{
    Derived1 d1 ;
    Derived2 d2 ;
    std::cout<<d1.flag<<" "<<d2.flag<<std::endl ;
    return 0 ;
}

編集

「軌道上の明度レース」で指摘されているように、ctorプロセス中のstatic_castは、Undefined Behabiour(UB)を引き起こす可能性があります。static_cast演算子の必要性を否定する更新された実装を次に示します。

#include <iostream>
struct Derived1 ;
struct Derived2 ;
namespace BootstrapDetail
{
    template <typename Identifier> bool init();
    template <> bool init <Derived1>() { return true ; }
    template <> bool init <Derived2>() { return false ; }
}
template <typename Derived> struct Bootstrap
{
    Bootstrap(): flag(BootstrapDetail::init<Derived>()) {}
    bool flag ;
};
struct Derived1: public Bootstrap <Derived1> {};
struct Derived2: public Bootstrap <Derived2> {};
int main()
{
    Derived1 d1 ;
    Derived2 d2 ;
    std::cout<<d1.flag<<" "<<d2.flag<<std::endl ;
    return 0 ;
}
于 2013-02-04T12:29:14.787 に答える