处理一般情况下混合类型和非类型的可变参数模板

问题描述 投票:0回答:1

所以我正在尝试制作一个类型特征来说明两个“外部”类类型是否相同。

即。

std::vector<int>
std::vector<double>
相同,我不关心我的类型特征的任何内部参数。

我在尝试为此创建通用类型特征时遇到的一个问题是,我只知道如何处理typed可变参数模板separatelynon-typed,这似乎阻止我制作它通用。

是否可以处理类型化和非类型化模板参数的任何排列?

这是我已经实施的(包括它失败的例子):

// g++ -std=c++17

#include <iostream>
#include <vector>
#include <array>
#include <type_traits>

// If the outer types don't match
template <typename, typename>
struct is_outer_type_same : std::false_type {};


// if the arguments of the compared Type contains only types
// ie. std::vector<int,std::allocator<int>>
// (the inner arguments are also types)

template <template<typename...> typename OuterType,
                   typename... InnerTypes1,
                   typename... InnerTypes2
         >
struct is_outer_type_same < OuterType<InnerTypes1...>,
                            OuterType<InnerTypes2...>
                          >
        : std::true_type {};


// if the arguments of the compared Type contains only non-types
// eg. SomeClassName<4,5,2>

template <template<auto...> typename OuterType,
                   auto... InnerVariables1,
                   auto... InnerVariables2
         >
struct is_outer_type_same < OuterType<InnerVariables1...>,
                            OuterType<InnerVariables2...>
                          >
        : std::true_type {};


// if the arguments of the compared Type contains a single
// typed-argument followed by some non-typed arguments
// ie. std::array<int, 4>

template <template<typename, auto...> typename OuterType,
        typename InnerType1, auto... InnerVariables1,
        typename InnerType2, auto... InnerVariables2
         >
struct is_outer_type_same < OuterType<InnerType1, InnerVariables1...>,
                            OuterType<InnerType2, InnerVariables2...>
                          >
        : std::true_type {};


// For any outer types whose arguments have the pattern:
// single variable argument followed by a sequence of typed arguments:

template <template<auto, typename...> typename OuterType,
    auto InnerVariable1, typename... InnerTypes1,
    auto InnerVariable2, typename... InnerTypes2
         >
struct is_outer_type_same < OuterType<InnerVariable1, InnerTypes1...>, 
                            OuterType<InnerVariable2, InnerTypes2...>
                          >
        : std::true_type {};


// This is to make it neater to evaluate:

template <typename S, typename T>
inline constexpr bool is_outer_type_same_v
                    = is_outer_type_same<S,T>::value;


// Example type that fails to be handled
// correctly by the above struct templates: 
template <typename A, typename B, int C>
struct ExampleType
{
    A data1;
    B data2;
    const int data3 = C;
};


int main ()
{   
    // Examples to show where it fails:

    std::cout << "Fails to find match for ExampleType: "

    << is_outer_type_same_v<ExampleType<double,int,2>,
                            ExampleType<double,int,2>>

    << std::endl << std::endl



    // Examples to show where it works:

    << "Finds correctly: " << std::endl


    << std::endl << "Matches for std::vector: "

    << is_outer_type_same_v<std::vector<int>,
                            std::vector<double>>

    << is_outer_type_same_v<std::vector<std::vector<int>>,
                            std::vector<double>>

    << is_outer_type_same_v<std::vector<std::array<int,3>>,
                            std::vector<double>>


    << std::endl << "Mismatches for std::vector: "

    << is_outer_type_same_v<int,
                            std::vector<int>>

    << is_outer_type_same_v<std::array<int, 3>,
                            std::vector<int>>

    << is_outer_type_same_v<std::array<std::vector<int>, 3>,
                            std::vector<int>>


    << std::endl << "Matches for std::array: "

    << is_outer_type_same_v<std::array<int, 3>,
                            std::array<double, 7>>

    << is_outer_type_same_v<std::array<std::vector<int>, 7>,
                            std::array<double, 2>>

    << is_outer_type_same_v<std::array<std::array<int,3>, 8>,
                            std::array<std::vector<double>, 5>>


    << std::endl << "Mismatches for std::array: "

    << is_outer_type_same_v<int,
                            std::array<int,2>>

    << is_outer_type_same_v<std::vector<int>,
                            std::array<int,8>>

    << is_outer_type_same_v<std::vector<std::array<int,3>>,
                            std::array<int,2>>

    << std::endl;

    return 0;
}
c++ variadic-templates template-meta-programming generic-programming typetraits
1个回答
0
投票

你能通用吗?还没有。但是有很多方法可以做到这一点(尽管它们不是最干净的)。

第一步是比较内部“值”。虽然结构模板参数不完全符合您的要求,但函数模板参数可以(您可以为 typename/auto 创建“重载”)。

所以有了这些知识,你可以做这样的事情:

enum version {
    type, value
};

template <version...EE>
struct version_list {};

template <version...EE>
inline constexpr version_list<EE...> VL {};


template <template <class> class C, class T1>
constexpr auto decompose(C<T1>&)     { return VL<type>; }

template <template <auto> class C, auto V1>
constexpr auto decompose(C<V1>&)     { return VL<value>; }

template <template <class, class> class C, class T1, class T2>
constexpr auto decompose(C<T1, T2>&) { return VL<type, type>; }

template <template <class, auto> class C, class T1, auto V1>
constexpr auto decompose(C<T1, V1>&) { return VL<type, value>; }

/* continue repeating for different variations... */

这将允许您像这样比较模板参数的数量/类型:

template <typename T>
using decompose_t = decltype(decompose(std::declval<T&>()));

template <version...EE1, version...EE2>
constexpr bool compare_versions(
    const version_list<EE1...>, 
    const version_list<EE2...>) 
{
    if constexpr(sizeof...(EE1) != sizeof...(EE2)) return false;
    else return ((EE1 == EE2) && ...);
}

template <typename T, typename U>
inline constexpr bool compare_versions_v 
     = compare_versions(decompose_t<T>{}, decompose_t<U>{});

最后,您可以像这样创建比较:

template <typename T, typename U>
constexpr bool is_outer_type_same() {
    if(compare_versions_v<T, U>) {
        /* Comparison logic */
    }
    else return false;
}

template <typename T, typename U>
inline constexpr bool is_outer_type_same_v = is_outer_type_same<T, U>();

如果外部类型没有相同的模板参数,您甚至不会尝试检查它们是否匹配。

我省略了实际的比较逻辑,因为它与您在第一次检查中所做的非常相似。您可能想要编写一些代码来生成所有这些函数并将它们写入一个文件,然后您可以将其包含/导入到实际公开的代码中。

但是如果我们有

typename auto
:P

,所有这一切都可以避免
© www.soinside.com 2019 - 2024. All rights reserved.