Вопрос

I want to check whether or not a template can be specialized using a given set of arguments. Here is the version for templates accepting only 1 argument:

#include <iostream>

template<template<typename...> class C, typename T>
struct is_valid_specialization {
    typedef struct { char _; } yes;
    typedef struct { yes _[2]; } no;

    template<template<typename...> class D, typename U>
    static yes test(D<U>*);
    template<template<typename...> class D, typename U>
    static no test(...);

    constexpr static bool value = (sizeof(test<C, T>(0)) == sizeof(yes));
};

template<typename T>
struct Test1 { };

template<typename T1, typename T2>
struct Test2 { };

template<typename...>
struct TestV { };

int main() {
    std::cout << "Test1<T>: " << is_valid_specialization<Test1, int>::value << std::endl;
    std::cout << "Test2<T>: " << is_valid_specialization<Test2, int>::value << std::endl;
    std::cout << "TestV<T>: " << is_valid_specialization<TestV, int>::value << std::endl;
}

This does the job for templates accepting only a single argument, but obviously I want to be able to use this with multiple arguments as well, so I tried this:

template<template<typename...> class C, typename... T>
struct is_valid_specialization {
    typedef struct { char _; } yes;
    typedef struct { yes _[2]; } no;

    template<template<typename...> class D, typename... U>
    static yes test(D<U...>*);
    template<template<typename...> class D, typename... U>
    static no test(...);

    constexpr static bool value = (sizeof(test<C, T...>(0)) == sizeof(yes));
};

Now this is where things get weird, because now value is always false.

Is there something I'm missing? What is so utterly different between these two versions? Is there another way to achieve this?

EDIT:
I've filed a bug report for both Clang and GCC

Это было полезно?

Решение

The following is easier and works:

template<template<typename...> class C, typename... T>
struct is_valid_specialization {
    typedef struct { char _; } yes;
    typedef struct { yes _[2]; } no;

    template<template<typename...> class D>
    static yes test(D<T...>*);
    template<template<typename...> class D>
    static no test(...);

    constexpr static bool value = (sizeof(test<C>(0)) == sizeof(yes));
};

Live example

Другие советы

The number of template parameters accepted by the function test (U...) is still not known even if you explicitly specify the first T... parameters. Additional U... template parameters might be deduced from the function parameters. Since the function parameter (0) doesn't help guessing the size of U..., the first template function is not instantiated. It is important to note that the template parameter D might also take an arbitrary number of parameters. The compiler shouldn't make any assumption.

GCC and Clang are right.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top