c++ 检查示例化类时使用的模板参数(编译时)

x8diyxa7  于 2022-12-27  发布在  其他
关注(0)|答案(3)|浏览(176)

我试着写一个元函数type_par_same_as,只要类的模板参数匹配给定的类型,它就选择true_type
演示

#include <type_traits>
#include <concepts>
#include <string>
#include <vector>
#include <cstdio>

template <template <typename...> class Template, typename T>
struct type_par_same_as_impl : std::false_type {};

template <template <typename...> class Template, typename... Args>
struct type_par_same_as_impl<Template<Args...>, Args...> : std::true_type {};

template <template <typename...> class Template, typename... Args>
concept type_par_same_as = type_par_same_as_impl<Template, Args...>::value;

int main()
{

    std::vector<int> vint;
    std::vector<std::string> vstring;
    if constexpr (type_par_same_as<decltype(vint), int>) {
        printf("Vector instantiated with type int!\n");
    }
}

这是我得到的:

<source>:11:56: error: type/value mismatch at argument 1 in template parameter list for 'template<template<class ...> class Template, class T> struct type_par_same_as_impl'
   11 | struct type_par_same_as_impl<Template<Args...>, Args...> : std::true_type {};
      |                                                        ^
<source>:11:56: note:   expected a class template, got 'Template<Args ...>'

我的方法是,一个原始模板的模板参数只接受模板的任何特殊化,比如std::vector(没有类型),然后我用SFINAE去掉与模板特殊化不匹配的类类型Template<Args...>(例如,std::vector<int>,如果int被指定为Args),并且我应该为所有可以这样做的类类型接收true_type。但我的逻辑似乎在某个时候出错了,我哪里错了?

9bfwbjaz

9bfwbjaz1#

下面是如何编译它:

template <class Template, typename... T>
struct type_par_same_as_impl : std::false_type {};

template <template <typename...> class Template, typename... Args>
struct type_par_same_as_impl<Template<Args...>, Args...> : std::true_type {};

template <class Template, typename... Args>
concept type_par_same_as = type_par_same_as_impl<Template, Args...>::value;

但是它不适用于您的测试用例,因为std::vector<int>实际上是std::vector<int, std::allocator<int>>,而您只传递了两个测试用例中的int

int main()
{

    std::vector<int> vint;
    std::vector<std::string> vstring;
    if constexpr (type_par_same_as<decltype(vint), int, std::allocator<int>>) {
        printf("Vector instantiated with type int!\n");
    }
}
am46iovg

am46iovg2#

如果在lorro's answer上展开,Args...被放置在非推导的上下文中,使得它们仅从显式传递的模板参数推导,而不是从示例化std::vector的参数推导,则这可以如最初预期的那样工作,通过利用std::type_identity

#include <type_traits>
#include <vector>

template <typename Template, typename... Args>
struct type_par_same_as_impl : std::false_type {};

template <template <typename...> typename Template, typename... Args>
struct type_par_same_as_impl<Template<std::type_identity_t<Args>...>, Args...>
    : std::true_type {};

template <typename Template, typename... Args>
concept type_par_same_as = type_par_same_as_impl<Template, Args...>::value;

static_assert(type_par_same_as<std::vector<int>, int, std::allocator<int>>);
static_assert(type_par_same_as<std::vector<int>, int>);
static_assert(not type_par_same_as<std::vector<int>, float>);

Try it on Compiler Explorer

kq4fsx7k

kq4fsx7k3#

我只是想添加一个解决方案,我刚刚发现,这可能是一个更通用一点。
除了比较第一个模板参数,还可以提取第n个模板参数并使用惯用的std::is_same<U,T>来比较它,这样用户就可以自由选择实际比较哪个模板参数:
演示

#include <type_traits>
#include <concepts>
#include <string>
#include <vector>
#include <tuple>
#include <cstdio>

template<std::size_t, typename>
struct nth_targ_of;

template<std::size_t N, template <typename...> class Template, typename... Args>
struct nth_targ_of<N, Template<Args...>> : std::tuple_element<N, std::tuple<Args...>> {};

template<std::size_t N, typename T>
using nth_targ_of_t = nth_targ_of<N, T>::type;

int main()
{
    std::vector<int> vint;
    std::vector<std::string> vstring;
    if constexpr(std::same_as<nth_targ_of_t<0, decltype(vint)>, int>) {
        printf("Vector instantiated with type int!\n");
    }
    if constexpr(std::same_as<nth_targ_of_t<0, decltype(vstring)>, std::string>) {
        printf("Vector instantiated with type string!\n");
    }
}

输出:

Vector instantiated with type int!
Vector instantiated with type string!

相关问题