C++ を C++98 (私は C 出身です) として使用するのではなく、C++11 を使用しようとしています。問題を解く。
通常、継承を使用してタイプに基づいてメソッドを追加し、ユーザーに依存しますが、特性を使用したいのですが、エンドユーザーが「カスタムのもの」を使用することを期待していません。これは実験だからです.
次のように、True と False の型を作成することから始めました。
struct True {
static const bool value = true;
};
struct False {
static const bool value = false;
};
次に、enable_if
構造体またはクラスが構造体 (C の意味ではサイズなど) と名前空間の両方であるという事実を使用することを理解している私の定義は、次のようになります。
template<bool B,class T>
struct EnableIf {};
template<class T>
struct EnableIf<true,T> {
typedef T type;
};
テンプレートTが何であれ、「タイプ」と呼ばれる「名前空間タイプのメンバー」(可能であれば)を持つことだけEnableIf
を期待しています。true
これはうまくいくようです。
false/default のケースは、アクセスしようとするとEnableIf<false,T>::type
、type
これまでのところすべてが正しいと確信していますが、冗長になっているだけです。
私のテストケース
私はテストの場としてリストを選択しました (ここでも調査中なので、標準セットは使用しません) 通常、これを行うにはクラス階層を使用しますlist
。余分なメンバーはint find(T*);
、T* が T の ID であるためです。
次に、これを and に拡張し、int find(T&);
int find(T&,int)
==int count(T&)
を使用して T を比較します。これは、ユーザーに任せることで意味することです。ユーザーは、タイプについて知っていることに基づいて、必要なリストを選択できます。
EnableIf
代わりにこれを行うために(後でstd::enable_if
自信を持って)使用したいのですが、テンプレートがスタンプアウトされたenable
場合、型がそのように使用できる場合にのみ機能が使用されます。
リスト定義
template<class T>
class List {
public:
typedef typename T::hasEquality hasEquality;
virtual ~List() {}
virtual T& operator[](int index) =0;
virtual const T& operator[](int index) const =0;
virtual void append(T*) =0;
virtual int length() const =0;
virtual
typename EnableIf<hasEquality::value, bool>::type
operator==(const List<T>& rhs) const {
if(length() == rhs.length()) {
for(int k=0;k!=length();k++) {
if(!((*this)[k] == rhs[k])) {
return false;
}
}
return true;
} else {
return false;
}
}
virtual
typename EnableIf<T::hasEquality::value, int>::type
count(const T& what) const =0;
};
セットではなくリストなので、順序が重要です。hasEquality
これは、次の意味で推移的であるべきであることがわかります。
もし T が等価の概念を持っているなら、T のリストも等価の概念を持っている
次に、単方向リストの実装に進みます。
試験の種類
class A {
public:
A(int value) { val = value; }
typedef True hasEquality;
bool operator==(const A& rhs) const {
if(val == rhs.val) {
return true;
}
return false;
}
private:
int val;
};
class B {
public:
typedef False hasEquality;
};
結果
int main(int,char**) {
LinkedList<A> listA;
listA.append(new A(6));
A a(6);
std::cout<<"there are "<<listA.count(a)<<" of them\n";
return 0;
}
ご想像のとおり、これは機能します。私の最初のテストには最初に B が含まれていましたが、それが問題を引き起こします。
int main(int,char**) {
LinkedList<A> listA;
listA.append(new A(6));
A a(6);
std::cout<<"there are "<<listA.count(a)<<" of them\n";
LinkedList<B> listB;
return 0;
}
これはそうではなく、次のように失敗します:
src/main.cpp: In instantiation of ‘class List<B>’:
src/main.cpp:77:7: required from ‘class LinkedList<B>’
src/main.cpp:176:16: required from here
src/main.cpp:59:2: error: no type named ‘type’ in ‘struct EnableIf<false, bool>’
operator==(const List<T>& rhs) const {
^
src/main.cpp:73:3: error: no type named ‘type’ in ‘struct EnableIf<false, int>’
count(const T& what) const =0;
^
src/main.cpp: In instantiation of ‘class LinkedList<B>’:
src/main.cpp:176:16: required from here
src/main.cpp:134:3: error: no type named ‘type’ in ‘struct EnableIf<false, int>’
count(const T& what) const {
^
make: *** [build/main.o] Error 1
何らかの理由で typename 行の後にエラー マーカーを配置しますEnableIf
。false
これがなぜなのかはよくわかりませんが、そうです、ありませんtype
が、これは設計によるものです!
リサーチ
http://en.cppreference.com/w/cpp/types/enable_if
それを引用するには:
template<bool B, class T = void>
struct enable_if {};
template<class T>
struct enable_if<true, T> { typedef T type; };
私のものは名前だけが異なり、デフォルトの T は無効です。これを私のものに追加しても(予想どおり)、問題は解決しません。
http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/SFINAE
http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/enable-if
私の考えを確認します。
ボーナス質問
constexpr と static
最初に私は試しstruct False { constexpr bool operator==(bool what) { return !what; } };
てみましたが、同じですTrue
。
しかし、これはうまくいきませんでした。「静的」という言葉を使用して operator== を修飾することはできconstexpr static bool is(bool what);
ませんが、同じ効果を得るために呼び出されたメソッドを使用できたのに、なぜ constexpr は静的を意味しないのでしょうか?
私の考えでは、constexprs は実際には存在せず、設計は仮想の反対のようなものです。インスタンスを使用して静的メソッドを呼び出すことができないと言うものは何もありません。C++03 標準を確認したところです。セクション 9.4 でこれが確認されています。 、これは変わりましたか?
スフィナエ
SFINAE を使用して、定義されていないFalse
場合を想定することは可能でしょうか? hasMember
これは基本的なタイプなどでは機能しないことを理解しています。これは実験です。自信が持てるまでは、これらの手法を本番環境で使用することはありません。