Проверьте, действительна ли специализация шаблона

Я хочу проверить, может ли шаблон быть специализированным с использованием заданного набора аргументов. Вот версия для шаблонов, принимающих только 1 аргумент:

#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;
}

Этот выполняет задание для шаблонов, принимающих только один аргумент, но, очевидно, я хочу иметь возможность использовать это с несколькими аргументами, поэтому я попробовал это:

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));
};

Теперь это то, где вещи становятся странными, потому что теперь значение всегда неверно.

Есть ли что-то, что мне не хватает? Что между этими двумя версиями так сильно отличается? Есть ли другой способ достичь этого?

EDIT:
Я опубликовал отчет об ошибке для Clang и GCC

Ответы

Ответ 1

Далее проще и работает:

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));
};

Живой пример

Ответ 2

Число параметров шаблона, принятое функцией test (U...), пока неизвестно, даже если вы явно указали первые параметры T.... Дополнительные параметры шаблона U... могут быть выведены из параметров функции. Поскольку параметр функции (0) не позволяет угадать размер U..., первая функция шаблона не создается. Важно отметить, что параметр шаблона D также может принимать произвольное количество параметров. Компилятор не должен делать никаких предположений.

GCC и Clang правы.