使用函数指针专门化模板,这取决于模板参数
Specialize template with function pointer, that depends on template parameter
我想要一个带有嵌套值的模板,它应该由给定的初始化函数初始化:
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>{};
附加问题:为什么偏特化不能依赖于模板参数?此限制背后的基本原理是什么?
如果只是在缺少第二个模板参数的情况下进行默认初始化,您可以提供一个模板化的默认初始化函数作为默认参数,例如。
template<typename T>
T do_default_assign() {
return T();
};
template <typename T, T (INIT)() = do_default_assign<T> > struct Foo
{
T value = INIT();
};
然而,这会遇到不必要的 "return by value" 和赋值操作,这对于某些 T 来说可能代价高昂或不可能。
对于您的情况,您可以使用:
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;
您可以定义一个 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();
};
我想要一个带有嵌套值的模板,它应该由给定的初始化函数初始化:
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>{};
附加问题:为什么偏特化不能依赖于模板参数?此限制背后的基本原理是什么?
如果只是在缺少第二个模板参数的情况下进行默认初始化,您可以提供一个模板化的默认初始化函数作为默认参数,例如。
template<typename T>
T do_default_assign() {
return T();
};
template <typename T, T (INIT)() = do_default_assign<T> > struct Foo
{
T value = INIT();
};
然而,这会遇到不必要的 "return by value" 和赋值操作,这对于某些 T 来说可能代价高昂或不可能。
对于您的情况,您可以使用:
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;
您可以定义一个 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();
};