Visual C++ 2008/2010に誤りがあります。しかし、それは複数の方法で取り組むことができます。
Foo<BasePolicy2> fb
のタイプを考えてみましょう。
この宣言では、テンプレートFoo <>の2番目のテンプレートパラメータが最初に宣言されているようにデフォルト設定されています。だから、明示的にそのタイプがある:
/*1*/ Foo<BasePolicy2,cool::enable_if<
cool::is_same<BasePolicy, BasePolicy2>::value ||
cool::is_same<BasePolicy2,BasePolicy2>::value
>::type
>
すでに/*1*/
はつまるところことに満足している場合:
/*2*/ Foo<BasePolicy2,void>
、あなたは以下、ランデブーで再び私たちを満たすことができます。
/*3/ cool::enable_if<
cool::is_same<BasePolicy, BasePolicy2>::value ||
cool::is_same<BasePolicy2,BasePolicy2>::value
>
に解決:
/*4/ cool::enable_if<some_boolean_consant>
次は、template enable_if<>
が定義されているかを確認しましょう。
まあ、我々はタイプがあることがわかりますnamespace cool
では、我々は持っている:
/*5/ template <bool, typename = void> struct enable_if {};
/*6/ template <typename T> struct enable_if<true, T> { typedef T type; };
ので/*4*/
ひいてはtemplate enable_if<>
の第二テンプレートパラメータをデフォルト設定、およびそのデフォルトのタイプがvoid
です。
その最初のブールパラメータは 値true
を有しており、その場合に、enable_if<>
が第2テンプレート のタイプを有するのtypedef type
をエクスポートしなければならないと言うたびに[OK]を、その後/*6*/
がその第2のテンプレートパラメータに対してtemplate enable_if<>
を専門パラメータ。最初のboolパラメータがfalse
の場合、そのtypedefは存在せず、コンパイラはbarfを返します。
さてさて、私たちはsome_boolean_consant == true
そして、/*4*/
がすべてでコンパイルするかどうかということを知っているし、エクスポートされたタイプtype
は のそれはenable_if<>
の不履行第二テンプレートパラメータです。 void
です。それはvoid
ある
/*7*/ cool::enable_if<
cool::is_same<BasePolicy, BasePolicy2>::value ||
cool::is_same<BasePolicy2,BasePolicy2>::value
>::type
:
Now'veは、の種類を推定しました。したがって、/*1*/
は/*2*/
になります。デフォルトのタイプはFoo<BasePolicy2>
です。
それがあるべきようですが、この結論の疑わしいされている場合は、単にグローバルスコープでプログラムにこれを追加してコンパイルします。
typedef cool::enable_if<
cool::is_same<BasePolicy, BasePolicy2>::value ||
cool::is_same<BasePolicy2,BasePolicy2>::value
>::type WhatType;
WhatType what_am_i;
コンパイラは言うだろう:
'what_am_i' : illegal use of type 'void'
を
またはその旨の単語。
ランデブー
= /*2/
/*1/
は私たちに質問を約あることのVisual C++のコンパイルエラーにいくつかの影響力を与えることを知識:
Error 1 error C2039: '{ctor}' : is not a member of 'Foo' main.cpp 25
エラーがコンストラクタは、それを生じさせることに不平を言っています実際には属している型で宣言されたコンストラクタではありません。つまり、 Foo<Policy>::Foo()
はFoo<Policy>
のコンストラクタではありません。
Foo<Policy>
の定義では、初期宣言の2番目のテンプレートパラメータがデフォルトで設定されています。これは、void
であることがわかります。したがって、 質問自体が表示されます:実際には、デフォルトの2番目のテンプレートパラメータをコンパイラが尊重していますか?つまり、 のテンプレート定義Foo<Policy>
がテンプレート定義のFoo<Policy,void>
であることを認識していますか?
template <typename Policy>
struct Foo<Policy,void> {
Foo();
};
template <typename Policy>
Foo<Policy,void>::Foo() {
}
は、プログラムはVisual C++でコンパイルクリーン:
答えは、我々は単に明示的にデフォルトの第二パラメータを指定するには、テンプレートとそのコンストラクタの定義を変更した場合についてはNoです。
Visual C++は、このエラーを起こして、Standard C++について議論の余地がありますか?それともちょうど壊れていますか? これはちょうど壊れています。
/* Simple Case */
template<typename X, typename Y = void>
struct A;
template<typename X>
struct A<X> {
A();
};
template<typename X>
A<X>::A(){};
int main()
{
A<int> aint;
return 0;
}
これは、それが消化不良を引き起こしているテンプレートメタプログラミング/*3*/
の一口だことを示して と質問者が指摘するように、場合:私たちは、この単純にそれをしようが、基本的に同じプログラムならば、それは問題ありませんので、その口に合ったものは、||
の操作を削除することで実験的に簡略化され、 がすべて正常です(もちろん、cool::
論理は壊れています)。
回避策はありますか?
私は既に見ました。 void
のテンプレートパラメータをFoo<Policy>
とFoo<Folicy>::Foo()
のように明示的に定義するだけです。あなたが知りたいことがあれば、今すぐに出ることができます。
しかし、それは痒みです。このレベルでバグが ではないことが判明した場合、修正レベルを/* Simple Case */
に適用しています。これは、コンパイラのテンプレートメタプログラミング作業が不明瞭であるため、かゆみがない 回避策は少なくともnamespace cool
に限定されます。 がblightersが飛行でインスタンス化してはいけません。ここで
は、私はすぐに私は忘れるようになる コンパイラの進展を期待したテンプレートメタプログラミング(TMP)ヘルパーテンプレートに関する注意のルールです。そのようなテンプレートは、コンパイル時のロジックを容易にするためにのみ 存在します。コンパイラが 型を再帰的に定義するだけでコンパイラがそのロジックを実行できるのであれば、少なくともインスタンス化の深さが保たれている限り、そのコンフォートゾーンにとどまる可能性があります。 コンパイル時のロジックを補完するために中間型をインスタンス化することが義務付けられている場合、その最も奇妙な ペッカジロが現れやすい。あなたはコンパイルロジックが値のみ、彼らが公開する静的または列挙定数の を取ることによって達成することができるようにあなたのTMPのヘルパークラスをコーディングした場合
は、その後、あなただけのためのすべての時間、 をインスタンス化するコンパイラを強要します静的または列挙された定数は値を取得します。
ケースでは、クラス/*3*/
は、その不思議な毒性のある||
操作です。 namespace cool
のTMPヘルパークラスは、不必要にブール定数のメタ論理を で行います。
TMPヘルパークラスの慎重なアプローチは、反復型定義によって、論理演算をインスタンス化しないですべてシミュレーションできるように定義することです。定数がエクスポートされる - 最終的に必要になるのは、コンパイル時 ロジックが正常に上陸しました。
namespace cool
{
template<bool val>
struct truth_type
{
static const bool value = false;
};
template<>
struct truth_type<true>
{
static const bool value = true;
};
typedef truth_type<true> true_type;
typedef truth_type<false> false_type;
template<class lhs,class rhs>
struct or_type
{
typedef false_type type;
};
template<class lhs>
struct or_type<lhs,true_type>
{
typedef true_type type;
};
template<class rhs>
struct or_type<true_type,rhs>
{
typedef true_type type;
};
template <typename T, typename = void> struct enable_if {};
template <typename T> struct enable_if<true_type, T> { typedef T type; };
template <typename T0, typename T1> struct is_same {
typedef false_type type;
};
template <typename T> struct is_same<T, T> {
typedef true_type type;
};
}
とテンプレートのFoo <の対応する宣言>次のようになります:namespace cool
の内容の慎重な再書き込みは次のようなものが見えるかもしれません
template <typename Policy,
typename = typename cool::enable_if<
typename cool::or_type<
typename cool::is_same<BasePolicy, Policy>::type,
typename cool::is_same<BasePolicy2, Policy>::type
>::type
>::type>
struct Foo;
この方法で、私たちのどれもcool::
シバン全体が でインスタンス化されるまで物事がインスタンス化されます:すべてのメタロジックの型だけを扱います。これらの変更がプログラムに行われた場合は、かゆみの回避策は必要ありません。 そしてGCCもそれに満足しています。
Visual Studioが実際に提供しているエラーは何ですか? –
@James:質問にエラーを追加しました – Samaursa
Dietmarがそのアプローチを提案した元の質問にリンクする必要があります。また、彼の答えにこの質問へのリンクを付けると、彼の注意を引くかもしれない。彼はこの質問に対する答えを知っていると確信しています。 –