模板模板类型的计数参数

moi*_*rex 6 c++ templates metaprogramming c++20

以下代码适用于 GCC(至少适用于 GCC 10.1.0),但不适用于 MSVC 和 Clang。我不确定它在 C++ 标准中是否合法。

我正在尝试计算template template类型中的参数。

以下代码是否为有效的 C++ 代码,如果是,那么如何使它们在 Clang 和 MSVC 中工作,如果不是,是否有替代方法?

编译器资源管理器上的代码

template <template<typename...> typename T>
struct template_count {
    static constexpr unsigned value = 0;
};

template <template<typename> typename T>
struct template_count<T> {
    static constexpr unsigned value = 1;
};

template <template<typename, typename> typename T>
struct template_count<T> {
    static constexpr unsigned value = 2;
};

template <template<typename, typename, typename> typename T>
struct template_count<T> {
    static constexpr unsigned value = 3;
};


template <typename one, typename two, typename three>
struct test {

};

int main() {
    return template_count<test>::value;
}
Run Code Online (Sandbox Code Playgroud)

moi*_*rex 2

经过twitter上某人的提示后,我找到了一个适用于 GCC 和 Clang 的更好的解决方案(链接到编译器资源管理器)(在 github 中):

#include <type_traits>
#include <cstddef>

struct variadic_tag {};
struct fixed_tag : variadic_tag {};
struct number_signature {};

template<std::size_t V>
struct ParameterNumber : number_signature {
    constexpr static auto value = V;
};

template<typename T>
concept NumberObjConcept = std::is_base_of_v<number_signature, T>;

template<template<typename> typename>
auto DeduceArgs() -> ParameterNumber<1>;

template<template<typename, typename> typename>
auto DeduceArgs() -> ParameterNumber<2>;

template<template<typename, typename, typename> typename>
auto DeduceArgs() -> ParameterNumber<3>;

template<template<typename, typename, typename, typename> typename>
auto DeduceArgs() -> ParameterNumber<4>;

template<template<typename, typename, typename, typename, typename> typename>
auto DeduceArgs() -> ParameterNumber<5>;

template<template<typename, typename, typename, typename, typename, typename> typename>
auto DeduceArgs() -> ParameterNumber<6>;

template<template<typename, typename, typename, typename, typename, typename, typename> typename>
auto DeduceArgs() -> ParameterNumber<7>;

template<template<typename, typename, typename, typename, typename, typename, typename, typename> typename>
auto DeduceArgs() -> ParameterNumber<8>;

template<template<typename, typename, typename, typename, typename, typename, typename, typename, typename> typename>
auto DeduceArgs() -> ParameterNumber<9>;

template<template<typename, typename, typename, typename, typename, typename, typename, typename, typename, typename> typename>
auto DeduceArgs() -> ParameterNumber<10>;

template<template<typename...> typename F>
auto DeduceTemplateArgs(variadic_tag) -> ParameterNumber<1000000000>; // a meaningless big number

template<template<typename...> typename F>
auto DeduceTemplateArgs(fixed_tag)    -> decltype(DeduceArgs<F>());

template <typename one, typename two, typename three>
struct test {

};

#define __DEDUCE_TEMPLATE_ARGS(c) decltype(DeduceTemplateArgs<c>(fixed_tag{}))

int main() {
    return __DEDUCE_TEMPLATE_ARGS(test)::value;
}

Run Code Online (Sandbox Code Playgroud)

当然,上面的代码在这种情况下会失败:

template <template<typename> typename>
struct test {};
Run Code Online (Sandbox Code Playgroud)

这对于大多数情况来说都很好。