2017-11-19 4 views
0

typeのエイリアスをfinalとしてマークすることはできますか(つまり、派生クラスでは再定義できません)。"typedef"を最終的にする(またはシミュレーションする)

#include <iostream> 
class B{ 
    public: using type=std::string; 
}; 
class D : public B{ 
    public: using type=int;  //<--- [1] I want a compile error here. 
}; 
int main(){ 
    typename D::type str="abc"; //<--- [2] This line is actually correct. 
} 

http://en.cppreference.com/w/cpp/language/finalによると、それは機能のみのためです。
回避策はありますか?

場合によっては不正なコーダとして役立つでしょう。

+0

最初に型エイリアスを上書きすることはできません。したがって、 'final'はむしろ誤解を招きます。 – chris

+0

@chrisありがとう、私は同意します。私はおそらく間違った言葉を使っています....まだ正しいものを知らない。 – cppBeginner

+0

あなたが_ // <--- [2]と言うとき、この行は実際には正しいです。あなたはそれがあなたが望むものであることを意味します。右? 'str' varは、それを再定義したので' int'型でなければなりません。 – realharry

答えて

4

いいえ、できません。

特性ベースのタイプは可能ですが、機械は醜いです。

分散型マップを、adlベースのタグ関数マップ経由で定義することができます。

template<class T>struct tag_t{constexpr tag_t(){} using type=T;}; 
template<class T>constexpr tag_t<T> tag{}; 

namespace trait { 
    template<class T> 
    constexpr void type_tag(tag_t<T>){} 
    template<class T> 
    using type=typename decltype(type_tag(tag<T>))::type; 
} 

// non-final alias 
struct A{ 
    friend constexpr tag_t<int> type_tag(tag_t<A>){return {};} 
}; 
// non-final alias 
struct A{ 
    friend constexpr tag_t<char> type_tag(tag_t<A>){return {};} 
}; 
// final alias 
struct B{ 
    template<class T, std::enable_if_t< std::is_base_of<B,T>{}, bool> =true> 
    friend constexpr tag_t<std::string> type_tag(tag_t<T>){return {};} 
}; 

は今 trait::type<>Aさん type_tag作品をオーバーライドしていますが Bと同じことをしようとした場合、あなたは長い不可解なエラーが発生します。

これは悪い計画です。

メタクラスはおそらくこのようなことをさせるでしょう。

一般に、これらの両方では、C++の新しいサブ言語を作成して、C++で強制しない制約を適用する必要があります。可能ではありますが、非常に正当な理由がある場合を除き、不適切なアドバイスをします。

+0

タグマジックで多くの質問に答えたことは面白いです。私はまたあなたが大きなものでこの1つに挑戦することを勇気づけて満足しています。感謝。 – cppBeginner

1

タイプを有効に非表示にするために列挙型やその他のダミーを使用する方法についての接線の答えです。

/* 
* Imagine everybody uses managed strings in our project throughout, 
* so everyone expects to be able to declare and print strings everywhere, 
* especially for debugging... 
*/ 
typedef OurInternalMangedStrings string; 
/***/ 

void InternalStringManager::ReallyDoingNastyInternalStuff() 
{ 
    // Within this code casually using managed strings 
    // to format error messages, etc, 
    // would be fatal as it will cause nasty recursion. 
    enum DoNotUseStrings_DeadlockDanger { string, OurInternalMangedStrings }; 
    printError(string ("I had an error here and I don't know why - code ") << errCode); 

} 

これは、手がかりを与えて、うまくいけば、文字列とDoNotUseStrings_DeadlockDangerの両方に言及しますエラーを生成します。

しかし、「文字列」という単語を作成者が使用するのを止めている間は、タイプが限定されているため、コードが自動的に変換を実行したり、既に存在するタイプのオブジェクト個人的に

void MyManager::Setup() 
{ 
    { SomeFeature newPimple = new Somefeature; 
     enum DoNotUseMember {someFeature}; 

     /** set up newPimple using other member data and parameters 
      when it is ready I will assign it to the member variable "someFeature" 
      **/ 
     /** any accidental use of a someFeature member will produce error message **/ 
     // Ready to install the new pimpl as the visible feature 
     MUTEX_RAII(access_feature); // ... Or whatever might be needed 
     /* can still access someFeature by being explicit */ 
     delete this->someFeature; 
     this->someFeature = newPimpl; 
    } 
    /** other setup code that uses the new feature **/ 
} 

が、私は新しいインスタンスsomeFeatureを呼び出し、隠し行動になるだろう:データ値について

printError("I had an error here and I don't know why at all!"); 

が、私はより便利です見つける:コンストラクタは、明示的でない場合は、コメントせずに通過します、次の無料ですが、多くはnを見つける再読するのは難しいです。

このテクニックを使用する別の方法は、リファクタリングです。私は、幸せにメンバーの値を使ってその振る舞いを制御する方法を持っています。そして、制御値の1つを外部から制御しなければならない場合、拡張が必要です。これを実装するために、元の引数なしのメソッドはシムになり、そのメンバーを引数として新しいメソッドを呼び出します。

しかし、新しいメソッドが確実に引数の代わりにメンバを使用することはありませんか?個人的には、私は引数のマスクをメンバーにしたいと思いますが、私たちはもう一度他人の理解に制限されます。

+0

ありがとうございます。それは有用で創造的です。 – cppBeginner

関連する問題