1

私はジェネリック クラスを実装しています。これは、異なる型のセットに対して異なる動作をする必要があります (異なる個別の型だけでなく)。目標は、さまざまなタイプのオブジェクトをシリアル化して、カスタム プロトコル経由で送信することです (ただし、これは実用的なものではなく、より教育的なタスクです。私は分散コンピューティングに関心のある学生です)。たとえば、浮動小数点数と整数を別々に送信する必要があります。また、他の POD タイプのデフォルト ハンドラーも必要です。しかし、一部の POD タイプの動作をオーバーライドする必要があります...

SFINAE メソッドが非常に便利であり、SFINAE の原則と部分的な特殊化を使用するカスタム型に対して、整数型と浮動小数点型のジェネリック クラスを実装することがわかりました (以下のコードを参照)。しかし、他のハンドラーがより一般的な POD タイプのハンドラーとオーバーラップすることを期待して、他の POD タイプのハンドラーを実装しようとすると、あいまいさの問題に直面しました。実際、POD 型とそのサブセット (整数型と浮動小数点型) に対する GenericObject クラスの可能な特殊化の重複はありません。

私は特殊化の手動順序付けを実装しようとしていました。部分的な順序付けについてよく読んでください。ある特殊化がより特殊化されている場合、別の特殊化よりも優先されるということについてです。しかし、私は問題を解決できませんでした。部分的な専門化を手動で明確にする方法がわかりません。

POD 型ハンドラーの浮動小数点型と整数型のセットを除外するソリューションは、私には受け入れられません。この方法では、ハンドラー間に過剰な依存関係が生じるためです。私の問題を解決する正しい方法があることを願っています。たとえば、プログラムの開始時に、すべての静的リソースがいくつかの優先度で初期化されます。GCC では、属性コンストラクター __ attribute__((constructor(101))) または同様の属性 init_priority を使用して、このような初期化のシーケンスを制御できます。テンプレートの部分特化をそういう風に並べ替えていただけると嬉しいです。

何か提案していただけますか?

これが私のコードです:

#include <type_traits>
#include <iostream>
#include <cxxabi.h>

// General form
template <typename T, typename Enable0 = void>
struct GenericObject {
    char * description() {
        return (char *)"Undefined";
    }
};

// Specialization for integral types
template <typename T>
struct GenericObject<T, typename std::enable_if<std::is_integral<T>::value>::type> {
    char * description() {
        return (char *)"Integral";
    }
};

// Specialization for real types
template <typename T>
struct GenericObject<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
    char * description() {
        return (char *)"Real";
    }
};

// Specialization for other POD types. It MUST be less specialized than specializations for real and integral types, because in other way there will be an ambiguity, because every integral type is also a POD.
/*

    HERE IS MY PROBLEM

*/
template <typename T>
struct GenericObject<T, typename std::enable_if<std::is_pod<T>::value>::type> {
    char * description() {
        return (char *)"POD";
    }
};

// Declaration of types
struct IAmDefined {};
struct IAmUndefinedPOD {};
struct IAmUndefinedComplexClass : virtual IAmUndefinedPOD {};

// Specialization for IAmDefined class and also the most specialized template specialization.
template <>
struct GenericObject<IAmDefined> {
    char * description() {
        return (char *)"Defined";
    }
};

// Produces nice output
std::string demangle(const char *raw) {
    int status;

    char *demangled = abi::__cxa_demangle(raw, 0, 0, &status);
    std::string result(demangled);
    free(demangled);

    return result;
}

template <typename T>
void testObject() {
    GenericObject<T> object;
    std::cout << demangle(typeid(T).name()) << ": " << object.description() << std::endl;
}

int main() {    
    testObject<int>(); // Integral
    testObject<long>(); // Integral
    testObject<float>(); // Real
    testObject<double>(); // Real
    testObject<void>(); // POD
    testObject<IAmDefined>(); // Defined
    testObject<IAmUndefinedPOD>(); // POD
    testObject<IAmUndefinedComplexClass>(); // Undefined
}

コンパイル時のエラーは次のとおりです。

g++ --std=c++11 main.cc -o specialization-of-sets
main.cc: In instantiation of 'void testObject() [with T = int]':
main.cc:85:21:   required from here
main.cc:68:22: error: ambiguous class template instantiation for 'struct GenericObject<int, void>'
main.cc:15:8: error: candidates are: struct GenericObject<T, typename std::enable_if<std::is_integral<_Tp>::value>::type>
main.cc:36:8: error:                 struct GenericObject<T, typename std::enable_if<std::is_pod<_Tp>::value>::type>
main.cc:68:22: error: 'GenericObject<int, void> object' has incomplete type
main.cc: In instantiation of 'void testObject() [with T = long int]':
main.cc:86:22:   required from here
main.cc:68:22: error: ambiguous class template instantiation for 'struct GenericObject<long int, void>'
main.cc:15:8: error: candidates are: struct GenericObject<T, typename std::enable_if<std::is_integral<_Tp>::value>::type>
main.cc:36:8: error:                 struct GenericObject<T, typename std::enable_if<std::is_pod<_Tp>::value>::type>
main.cc:68:22: error: 'GenericObject<long int, void> object' has incomplete type
main.cc: In instantiation of 'void testObject() [with T = float]':
main.cc:87:23:   required from here
main.cc:68:22: error: ambiguous class template instantiation for 'struct GenericObject<float, void>'
main.cc:23:8: error: candidates are: struct GenericObject<T, typename std::enable_if<std::is_floating_point<_Tp>::value>::type>
main.cc:36:8: error:                 struct GenericObject<T, typename std::enable_if<std::is_pod<_Tp>::value>::type>
main.cc:68:22: error: 'GenericObject<float, void> object' has incomplete type
main.cc: In instantiation of 'void testObject() [with T = double]':
main.cc:88:24:   required from here
main.cc:68:22: error: ambiguous class template instantiation for 'struct GenericObject<double, void>'
main.cc:23:8: error: candidates are: struct GenericObject<T, typename std::enable_if<std::is_floating_point<_Tp>::value>::type>
main.cc:36:8: error:                 struct GenericObject<T, typename std::enable_if<std::is_pod<_Tp>::value>::type>
main.cc:68:22: error: 'GenericObject<double, void> object' has incomplete type

私はGCC 4.8を使用しています:

gcc バージョン 4.8.0 20120314 (実験的) [トランク リビジョン 185382] (Ubuntu/Linaro 20120314-0ubuntu2)

前もって感謝します。

4

2 に答える 2

7

個人的には、クラス テンプレートの部分的な特殊化ではなく、オーバーロードでこれを解決します。このようにして、タイブレーカーを簡単に導入できます。

template<class T> struct type{};

namespace detail{
template<class T> using Invoke = typename T::type;
template<class C, class T = void> using EnableIf = Invoke<std::enable_if<C::value, T>>;
template<class T> using EType = type<EnableIf<T>>;

// we need two tie-breakers here, one for general vs specialized case
// and one for specialized vs more specialized case
template<class T>
char const* describe(EType<std::is_integral<T>>, int, int){ return "Integral"; }
template<class T>
char const* describe(EType<std::is_floating_point<T>>, int, int){ return "Real"; }
template<class T>
char const* describe(EType<std::is_pod<T>>, int, long){ return "POD"; }
template<class T>
char const* describe(type<void>, long, long){ return "Undefined"; }
} // detail::

template<class T>
char const* describe(type<T>){
  // literal '0' is 'int', as such 'int' overloads are preferred
  return detail::describe<T>(type<void>(), 0, 0);
}

// ...

// simple overload for specialized types
char const* describe(type<IAmDefined>){
  return "Defined";
}

実例。カテゴリにvoid属していることに注意してください。POD ではありません。"Undefined"

于 2012-10-27T12:14:13.287 に答える