6

最後に編集

テンプレートを取る関数があります:

template <template <typename ...> class P, typename ... Args>
void f(const P<Args...> &p)
{
    std::cout << "Template with " << sizeof...(Args) << " parameters!\n";
}

これまでにテストしたどの種類のテンプレートでもうまく機能します。

f(std::valarray<int>{});    // Prints: "Template with 1 parameters!"
f(std::pair<char, char>{}); // Prints: "Template with 2 parameters!"
f(std::set<float>{});       // Prints: "Template with 3 parameters!"
f(std::map<int, int>{});    // Prints: "Template with 4 parameters!"

しかし、2 つのパラメーターを持つテンプレートを受け取る場合にテンプレートを特殊化したい場合、以下のコードは機能しません。

template <>
void f<template <typename, typename> class P, typename A, typename B>(const P<A, B> &p)
{
    std::cout << "Special case!\n";
}

parse error in template argument list
 void f<template <typename, typename> class P, typename A, typename B>(const P<Args...> &p) { std::cout << "Template with " << sizeof...(Args) << " parameters!\n"; }
      ^
'P' does not name a type
 void f<template <typename, typename> class P, typename A, typename B>(const P<Args...> &p) { std::cout << "Template with " << sizeof...(Args) << " parameters!\n"; }
                                                                             ^
expected ',' or '...' before '<' token
 void f<template <typename, typename> class P, typename A, typename B>(const P<Args...> &p) { std::cout << "Template with " << sizeof...(Args) << " parameters!\n"; }
                                                                              ^
template-id 'f<<expression error> >' for 'void f(int)' does not match any template declaration
 void f<template <typename, typename> class P, typename A, typename B>(const P<Args...> &p) { std::cout << "Template with " << sizeof...(Args) << " parameters!\n"; }

私の知る限り、他のタイプのテンプレートパラメーターを使用すると非常に簡単です。

// Type parameter
template <typename TYPE>
void f(TYPE) { std::cout << "Type!\n"; }

// Non-type parameter
template <int VALUE>
void f() { std::cout << "Value " << VALUE << "!\n"; }

// Type parameter specialization
template <>
void f(float) { std::cout << "Special type case!\n"; }

// Non-type parameter specialization
template <>
void f<666>() { static_assert(false, "Forbidden number!"); }

template-template テンプレートを使用してこの機能を実現するにはどうすればよいですか?

編集:

orlpangew関数テンプレートで指摘されているように、部分的に特殊化することはできないため、オブジェクト テンプレートに固執する必要があります。これが私の試みです。

template <template <typename ...> class P, typename ... Args>
struct c
{
    using type = P<Args...>; 
    const std::size_t count = sizeof...(Args);

    void f(const type &t)
    {
        std::cout << "Template with " << sizeof...(Args) << " parameters!\n";
    }
};

template <template <typename, typename> class P, typename A, typename B>
struct c<P, A, B> 
{
    using type = P<A, B>; 

    void f(const type &t)
    {
        std::cout << "Spezialized 2 parameters!\n";
    }
};

できます:

c<std::valarray, int>                    c_valarray_int;
c<std::pair, int, char>                  c_pair_int_char;
c<std::vector, int, std::allocator<int>> c_vector_int;
c<std::map, int, int>                    c_map_int_int;

c_valarray_int.f({});  // Prints: "Template with 1 parameters!"
c_pair_int_char.f({}); // Prints: "Spezialized with 2 parameters!"
c_vector_int.f({});    // Prints: "Spezialized with 2 parameters!"
c_map_int_int.f({});   // Prints: "Template with 2 parameters!" (expected)

しかし今は、コンパイラーにすべてを推測させるのではなく、すべてのパラメーターを指定する必要があります... それは悲劇ではありません。

4

2 に答える 2

4

関数テンプレートの部分的な特殊化 ( 2 つのテンプレート パラメーターを持つ任意のテンプレートの特殊化) を試みています。これは C++ では許可されていません。関数テンプレートを部分的に特化することはできません。

別の見方をすると、tempalte 型パラメーターとテンプレートの非型パラメーターに対して示した明示的な特殊化は、具体的な引数を使用します。関数テンプレートを明示的に特殊化するには、次のようにします。

template <>
void f<std::pair, int, double>(const std::pair<int, double> &p)
{
    std::cout << "Special case!\n";
}

元のコードではPABはまだ「バインドされていません」です。これらは引数ではなくパラメーターです。明示的な特殊化には、テンプレート パラメーターを含めることはできません。特殊化されるプライマリ テンプレートのすべてのテンプレート パラメーターは、その特殊化によって提供される具体的な引数にバインドする必要があります。


あなたの編集に対処するには:次のように、関数テンプレートインターフェイスを引数推定で保持し、呼び出しを(部分的に特殊化されている可能性がある)クラステンプレートに転送するだけです。

template <template <typename ...> class P, typename ... Args>
struct c
{
    using type = P<Args...>; 
    static const std::size_t count = sizeof...(Args);

    static void f(const type &t)
    {
        std::cout << "Template with " << sizeof...(Args) << " parameters!\n";
    }
};

template <template <typename, typename> class P, typename A, typename B>
struct c<P, A, B> 
{
    using type = P<A, B>; 

    static void f(const type &t)
    {
        std::cout << "Spezialized 2 parameters!\n";
    }
};

template <template <class ...> class P, class... Args>
void f(const P<Args...> &t)
{
    c<P, Args...>::f(t);
}

【実例】

于 2015-03-13T09:28:14.880 に答える
2

さて、あなたがやろうとしていることを行うための適切な構文は次のとおりです。

template <template<typename, typename> class P, typename A, typename B>
void f<P, A, B>(const P<A, B> &p) {
    std::cout << "Special case!\n";
}

ただし、これは部分的な特殊化であり、関数では許可されていません。ただし、静的メソッドを使用して関数をクラスに変換し、クラスの静的メソッドを呼び出すラッパー関数を使用できます。

于 2015-03-13T09:28:08.433 に答える