6

decltypeC ++ 11の結果を比較する方法はありますか?

つまり、このコードが無効なのはなぜですか。

template<typename T, typename U>
void func(T& t, U& u) {
    if(decltype(t) == decltype(u)) {
        // Some optimised version for this case
    } else {
        // A more general case for differing types
    }
}

場合によっては、この特定の問題は部分的なテンプレートの特殊化によって解決できることを知っています。私の質問はdecltypesの比較についてです。

編集: SFINAEを介して無料機能のデフォルトを提供しようとする過程で質問が出てきました。おそらくもっと良い質問は、なぜこれが無効なのかということでしょう。

template<bool B>
bool SomeFunction() { ... }

template<typename T, typename U>
bool SomeFunctionWrapper(T& t, U& u) {
    SomeFunction<decltype(t) == decltype(u)>();
}

それ以来、別の解決策(テンプレートをまったく含まない)を見つけましたが、ある段階でこれを試しました:

// If it exists, the free function is defined as
// bool AFreeFunction();
typedef struct { char } undefined;
template<typename T = void>
undefined AFreeFunction();

template<bool B>
bool AFreeFunctionWrapper_() {
    return false;
}

template<>
bool AFreeFunctionWrapper_<false>() {
    return AFreeFunction();
}

bool AFreeFunctionWrapper() {
    return AFreeFunctionWrapper_<decltype(AFreeFunction()) == decltype(undefined)>();
}

最終的に、GCC 4.6で動作するこの戦略のバリアントを入手しましたが、2012 RCでも、MSVCのテンプレート関数でデフォルトのテンプレート引数が許可されていないことを発見しました。したがって、最終的な解決策は次のようになります。

class AFreeFunction {
public:
    operator bool() { return false; }
};

関数が定義されている場合は、呼び出されます。そうでない場合は、代わりにクラスのコンストラクターとして解釈され、暗黙的ににキャストされboolます。

4

3 に答える 3

9

通常、この問題はタグのディスパッチによって解決します。tまた、すでにとu-T&との「宣言された型」をU&それぞれ持っています。型を比較して等しいかどうかを調べるには、 を使用できますstd::is_same。ただし、オーバーロードの解決により、この問題は既に解決されています。

template<class T>
void f(T& v1, T& v2){ ... } // #1

template<class T, class U>
void f(T& t, U& u){ ... } // #2

f両方の引数が同じ型である場合、#1 は #2 よりも特殊化されています。なんらかの理由で、手動の型比較でこれを解決することを主張する場合、前述のポイントを適用すると、次のようになります。

#include <type_traits>

namespace detail{
template<class T, class U>
void f(T& t, U& u, std::true_type){ ... } // #1

template<class T, class U>
void f(T& t, U& u, std::false_type){ ... } // #2
} // detail::

template<class T, class U>
void f(T& t, U& u){
  detail::f(t, u, std::is_same<T,U>()); // tag dispatching
}

std::is_samestd::true_type両方のタイプが同じ場合はから派生し、そうでない場合はから派生しstd::false_typeます。

于 2012-08-08T10:44:54.333 に答える
6

なぜ無効なのですか?a の結果decltypeは、まあ、型です。だからそれは次のようなことを言っています

if (int == int)

これは言語が明らかに許可していません。

関数の 2 つの部分を分離し、特殊な部分を特殊なクラスの関数内に配置し、そこに呼び出しを転送する必要があります。痛いです。

または、typeid実装が正しく実装されている場合は、実行時の型情報を使用することもできますが、その場合、すべてがプログラムの実行時に延期されます (これにより、最適化が少なくなります)。

于 2012-08-08T09:35:31.473 に答える
4

SFINAE ( std::enable_if)を使用してこれを行うことができます。

template<typename T, typename U>
typename std::enable_if<std::is_same<T, U>::value, void>::type func(T& t, U& u) {
    std::cout << "same\n";
}
template<typename T, typename U>
typename std::enable_if<!std::is_same<T, U>::value, void>::type func(T& t, U& u) {
    std::cout << "different\n";
}

Mehrdad が言うように、decltype(t)anddecltype(u)は型 (T &およびU &それぞれ) であり、値ではないため、値式レベルで比較することはできませんが、メタ式 (テンプレート) レベルで比較する必要があります。

于 2012-08-08T10:00:47.433 に答える