2012-04-11 20 views
3

現在、複雑な構造の内部要素にconstまたは非const参照としてアクセスできるようにするインターフェイスクラスを作成しています。いくつかのモジュールにはconstアクセスが与えられ、いくつかのモジュールにはフルアクセスが許可されるという考え方です。メンバ関数にconst修飾子を追加する

私は 'type_traits' std :: add_constを使用して内部メンバー関数の戻り値の型を条件付きで修飾しましたが、残念ながらconstまたはnon-constとしてメンバー関数を条件付きで修飾する方法は考えられません。

これも可能ですか?もしそうなら、どのように?

例えば:

template< typename T, bool isConst > 
struct apply_const 
{ 
    typedef T type; 
}; 

template<typename T> 
struct apply_const<T, true> 
{ 
    typedef typename std::add_const<T>::type type; 
}; 

template< bool isConst > 
const Interface 
{ 
    /// @brief get the TypeA member 
    typename apply_const<TypeA, isConst >::type& GetXpo3Container() // how do I conditionally add a const qualifier 
    { 
     return config_.type_a_member_; 
    } 

    typename apply_const<Profile, isConst >::type& GetProfile(unint32_t id) // qualifier ??? 
    { 
     return config_.profiles.get(id); 
    } 

    // .... lots more access functions 

    ConfigType config_; // the config 
}; 

注: - 書き込み可能としないものである一つのインタフェースの2つのバージョンを作成する/分離するための根本的な理由は、それらがconfigの異なるインスタンスへのアクセスを提供することです。開発中のサブシステムは、<running><candidate>構成をサポートする組み込みNetconfエージェントです。

+0

2つのオーバーロード(1つのconstと1つの非const)を使用し、SFINAEを使用して一度に1つのみを有効にします。 – ildjarn

+0

2つのオーバーロードでは、実際には何も保存されません(下記参照)。目的は2つのバージョンの 'インターフェース'を提供することです。ここではすべてのメンバー関数は 'const'参照を返し、もう1つはすべてのメンバー関数が非const参照を返します。戻り値の型は、メンバ関数の資格だけで問題にはなりません。私はメンバー機能についての資格がなくて済むようにしなければならないと思う。それはあまり問題ではない。 – mark

答えて

5

これは専門で行うことが最も簡単なようだ:

template< bool isConst > 
struct Interface; 

template <> 
struct Interface<false> 
{ 
    TypeA& GetXpo3Container() 
    { 
     return config_.type_a_member_; 
    } 
}; 

template <> 
struct Interface<true> 
{ 
    const TypeA& GetXpo3Container() const 
    { 
     return config_.type_a_member_; 
    } 
}; 

編集:私は完全にわからないが、これが追加されますどのような。

struct Interface 
{ 
    TypeA::type& GetXpo3Container() 
    { 
     return config_.type_a_member_; 
    } 
    const TypeA::type& GetXpo3Container() const 
    { 
     return config_.type_a_member_; 
    } 
}; 

を持っており、適切な場合にconst Interfaceを使用することは簡単ではないでしょうか?それとも、これは別の理由でオプションではありませんか?

編集2:私のstd::enable_ifの使用が間違っていました。

+1

'std :: enable_if :: type'は' Interface'のスコープに依存しないので、これはソフトエラーではなく、ハードエラーとなります(同じことが他の条件にも適用されます)。 –

+0

@LucDantonあなたが既にコメントしたときに私は実際に編集していましたが、ありがとう、あなたは正しいです:) – hvd

1

isConstがtrueの場合にテンプレートを特殊化し、すべてのメンバー関数constをこの場合はプライマリテンプレートのconstのままにしておくことができます。

また、メンバ関数の2つのバージョン(1つはconst、もう1つは無効)を作成し、enable_ifを使用すると適切なオーバーロードが有効になります。

1

あなたはSFINAEを使用することができます。

template<bool isConst> 
struct Interface 
{ 
    template< 
     bool Cond = isConst 
     , typename std::enable_if<!Cond, int>::type = 0    
    > 
    TypeA& 
    GetXpo3Container() const 
    { 
     return config_.type_a_member_; 
    } 

    template< 
     bool Cond = isConst 
     , typename std::enable_if<Cond, int>::type = 0 
    > 
    TypeA const& 
    GetXpo3Container() const 
    { 
     return config_.type_a_member_; 
    } 
}; 

注2人のメンバーは、テンプレートを作って、私が依存するようにtypename std::enable_if<Cond, int>::typeを強制的にデフォルトのパラメータを使用していることが必要であること - クラスstd::enable_if<isConst, int>::typeの範囲にに依存しないため、クラスがインスタンス化されるときにハードエラーが発生しますが、SFINAEが必要です。

ただし、デフォルトのパラメータは、誰かができることを意味します。 Interface<true> f; TypeA& ref = f.GetXpo3Container<false>();

template<typename T, T Value, typename> 
struct depend_on_c { 
    static constexpr T value = Value; 
}; 

/* and in the scope of Interface: */ 
    template< 
     typename Dummy = void 
     , typename std::enable_if< 
      depend_on_c<bool, isConst, Dummy>::value 
      , int 
     >::type = 0 
    > 
    /* rest as before */ 
:あなたはそれを避けたい場合は、ここで、おそらくより適切である std::enable_if依存再びのメンバー typeを作るための別の方法でだが、やや難解な(例えば、あなたのインターフェイスの未指定ビットを誤用しないようにユーザーを信頼していません)
関連する問題