如何从可变参数模板参数为函数“生成”模板规范?

问题描述

我想我会先展示这个例子然后再解释它:

#include <array>

template<typename T_,size_t size_>
struct arg
{
    using T = T_;
    static constexpr size_t size = size_;
};

template<typename... Arugments>
struct Foo
{
    template<typename Argument>
    std::array<typename Argument::T,Argument::size>& getArray() // specializations of all args in Arguments should be generated
    {
        static std::array<typename Argument::T,Argument::size> arr;
        return arr;
    }
};

int main()
{
    Foo<arg<int,10>,arg<float,1>> myFoo;
    myFoo.getArray<arg<int,10>>();
    myFoo.getArray<arg<float,10>>(); // should return a different array than the line above
    myFoo.getArray<arg<bool,1>>(); // should NOT work because arg<bool,10> is was not passed to Foo
}

如果得到一个结构体 arg,其中包含如何在 arr 中构造 getArray 的信息。参数列表传递给 Foo。现在我希望为 getArray 中的每个 arg 生成 Arguments 的模板特化。如果没有为特定的 arg 生成专门化,我希望发生某种错误

我怎样才能做到这一点?

解决方法

您可以使用 static_assert 来确保 Argument 是带有辅助结构的 Arguments 的一部分。

#include <array>
#include <iostream>

template <typename... T>
struct contains;

template <typename T>
struct contains<T> : std::false_type {};

template <typename T,typename U,typename... Rest>
struct contains<T,U,Rest...> : contains<T,Rest...>  {};

template <typename T,T,Rest...> : std::true_type {};

template<typename T_,std::size_t size_>
struct arg
{
    using T = T_;
    static constexpr std::size_t size = size_;
};

template<typename... Arguments>
struct Foo
{
    template<typename Argument>
    std::array<typename Argument::T,Argument::size>& getArray() // specializations of all args in Arguments should be generated
    {
        static_assert(contains<Argument,Arguments...>(),"Invalid type");
        static std::array<typename Argument::T,Argument::size> arr;
        return arr;
    }
};

int main()
{
    Foo<arg<int,10>,arg<float,1>> myFoo;
    myFoo.getArray<arg<int,10>>()[5] = 7;
    myFoo.getArray<arg<float,10>>(); // should return a different array than the line above
    //myFoo.getArray<arg<bool,1>>(); // should NOT work because arg<bool,10> is was not passed to Foo

    Foo<arg<int,1>> myFoo2;
    std::cout << myFoo2.getArray<arg<int,10>>()[5];

    Foo<arg<int,arg<double,1>> myFoo3;
    std::cout << myFoo3.getArray<arg<int,10>>()[5];
}

还想指出,如代码所示,myFoomyFoo2 返回相同的数组,因为它们是完全相同的类型。

myFoo3 另一方面是一个单独的类型,这意味着 getArray 成员函数是一个单独的函数并且拥有它自己的相同类型数组的副本。