2015-05-29 92 views
9

我想有这应该由给定的初始化函数初始化嵌套值模板:专营模板与函数指针,这取决于模板参数

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

可以这样使用:

// 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; 

但是,如果没有提供的功能,模板应尽量默认初始化嵌套的价值,所以我试图专注模板:

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

的想法是使用这种方式:

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. 

但我刚刚发现模板部分特例类型不能依赖于其他模板类型,我得到的错误被粘贴如下:

error: type 'T (*)()' of template argument 'nullptr' depends on a template parameter template struct Foo


有没有办法实现我的目标?

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

额外的问题:为什么部分特例不能依赖于模板参数,如果它与模板变量的作品,以及这将是很好?这个限制背后的理由是什么?

回答

2

如果只是在缺少第二个模板参数的情况下进行默认初始化,则可以提供模板化默认初始化函数作为默认参数。

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

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

然而,这遭受不必要“的价值回归”和赋值操作这可能是一些T.

+0

接受这一个,没有从@ Jarod42中的一个,因为它是在1秒前回答的! –

3

对于你的情况昂贵的或不可能的,你可以使用:

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

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

而且然后用它喜欢:

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

Live demo

2

可以定义一个constructor模板功能,将初始化Type类型的值,然后把它作为一个默认的构造函数:

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

,然后用它作为函数的默认模板参数:

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

Live demo

+0

这种方法看起来不错,因为它允许将任何参数传递给构造函数,但是提供与'T(INIT)()'不兼容的'构造函数'是不可能的,所以最后:将所有'Args'转发给'构造函数'没有意义:( –

+0

@PaperBirdMaster真的,但现在你有一个更通用的'构造函数',它是一个有用的函数,可以用于任何类型的构造函数(用于其他目的),而不是硬编码的'default_construct'或者像其他人所建议的那样使用'do_default_assign'。 – Shoe