简体   繁体   English

使用函数指针的Specialize模板,取决于模板参数

[英]Specialize template with function pointer, that depends on template parameter

I would like to have a template with a nested value which should be initialized by a given initializer function: 我想有一个嵌套值的模板,应该由给定的初始化函数初始化:

template <typename T, T(INIT)()> struct Foo
{
    T value = INIT();
};

It can be used this way: 它可以这样使用:

// Some random type only instanceable through factory()
struct Bar
{
    int bar{};
private:
    // The only way to create a Bar is through factory()
    friend Bar factory();
    Bar() {};
};

Bar factory() { return {}; }

Foo<Bar, factory> foo;

But, if no function is provided, the template should try to default-initialize the nested value, so I've tried to specialize the template: 但是,如果没有提供函数,模板应该尝试默认初始化嵌套值,所以我试图专门化模板:

template <typename T> struct Foo<T, nullptr>
{
    T value{};
};

The idea is to use it this way: 我的想法是这样使用它:

struct Baz{};

Foo<Bar, factory> foo; // Nested Bar have Bar::bar initialized through factory function.
Foo<Baz>          baz; // No factory function needed, nested Baz default-initialized.

But I just discovered that template partial specialization types cannot rely on other template types, the error I'm getting is pasted below: 但我刚刚发现模板部分特化类型不能依赖其他模板类型,我得到的错误粘贴在下面:

error: type 'T (*)()' of template argument 'nullptr' depends on a template parameter template struct Foo 错误:模板参数'nullptr'的类型'T(*)()'取决于模板参数模板struct Foo


Is there a way to achieve my goal? 有没有办法实现我的目标? It would be nice if it works with template variables as well: 如果它也适用于模板变量会很好:

template <typename T, T(INIT)()> T Foo = INIT();
template <typename T>            T Foo<T, nullptr>{};

Extra question: Why partial specializations cannot depend on template parameters? 额外的问题:为什么部分专业化不能依赖于模板参数? What's the rationale behind this restriction? 这种限制背后的理由是什么?

For your case, you may use: 对于您的情况,您可以使用:

template <typename T>
T default_construct() { return T{}; }

template <typename T, T(INIT)() = &default_construct<T>>
struct Foo
{
    T value = INIT();
};

And then use it like: 然后使用它像:

Foo<int> f;
Foo<int, bar> b;

Live demo 现场演示

If it's only about doing a default initialization if the second template parameter is missing, you may provide a templated default initialization function as the default parameter like. 如果只是在缺少第二个模板参数的情况下进行默认初始化,则可以提供模板化的默认初始化函数作为默认参数。

template<typename T> 
    T do_default_assign() { 
        return T(); 
    };                                                                      

template <typename T, T (INIT)() = do_default_assign<T> > struct Foo 
    { 
        T value = INIT(); 
    };

This however suffers an unnecessary "return by value" and assignment operation which might be costly or impossible for some T. 然而,这会遭受不必要的“按价值返回”和分配操作,这对于某些人而言可能是昂贵的或不可能的。

You can define a constructor template function that will initialize a value of type Type and then use it as a default constructor: 您可以定义一个constructor模板函数,该函数将初始化Type的值,然后将其用作默认构造函数:

template<typename Type, typename... Args>
Type constructor(Args... args) { 
    return Type(std::forward<Args>(args)...);
}

and then use it as default template argument for the function: 然后将其用作函数的默认模板参数:

template <typename T, T(INIT)() = constructor<T>> struct Foo
{
    T value = INIT();
};

Live demo 现场演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM