【问题标题】:How can I "generate" template spezialations for a function from a variadic template argument?如何从可变参数模板参数为函数“生成”模板规范?
【发布时间】:2021-09-28 14:18:28
【问题描述】:

我想我会先展示例子,然后再解释:

#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, 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,其中包含如何在getArray 中构造arr 的信息。 args 列表被传递给Foo。现在我希望为Arguments 中的每个arg 生成getArray 的模板特化。如果没有为特定的 arg 生成专业化,我希望发生某种错误。

我怎样才能做到这一点?

【问题讨论】:

    标签: c++11 templates variadic-templates template-specialization


    【解决方案1】:

    您可以使用static_assert 确保ArgumentArguments 的一部分,并带有辅助结构。

    #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, typename... Rest>
    struct contains<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, 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, 10>, arg<float, 10>, arg<float, 1>> myFoo2;
        std::cout << myFoo2.getArray<arg<int, 10>>()[5];
    
        Foo<arg<int, 10>, arg<float, 10>, arg<double, 1>> myFoo3;
        std::cout << myFoo3.getArray<arg<int, 10>>()[5];
    }
    

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

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

    【讨论】:

    • 代码太多。一行修复有效:static_assert(((std::is_same_v&lt;Argument, Arguments&gt;) || ...), "Invalid type");
    • @n.1.8e9-where's-my-sharem。这是 C++11 而不是 C++17。折叠表达式仅在 C++17 中引入。
    • 好吧,您回答了我的问题,我在代码中犯了一个错误,因为正如您指出的那样,@super myFoo2 将具有与 myFoo 相同的数组。但是有没有解决方法,比如arr 就像一个非静态成员?我实际上更愿意做一个非静态成员模板,但这是不可能的。
    • 我实际上会为此打开一个新问题。
    • @2b-t 是的,错过了那个标签。
    猜你喜欢
    • 1970-01-01
    • 2016-12-01
    • 2011-08-26
    • 1970-01-01
    • 2021-10-01
    • 2016-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多