嵌套 class 构造函数中的父模板参数推导
Parent template argument deduction in nested class constructor
我正在尝试编写可以推导出父 class 模板的嵌套 class 的 "promotion" 构造函数。它适用于父 class,但不适用于嵌套 class。这是一个代码示例。
template <class T>
struct potato {
struct baked {
template <class O>
baked(const typename potato<O>::baked& p)
: something(static_cast<T>(p.something)) {
}
baked() = default;
T something;
};
template <class O>
potato(const potato<O>& p)
: mybaked(p.mybaked) {
}
potato() = default;
baked mybaked;
};
int main(int, char**) {
potato<int> potato1;
potato<short> potato2(potato1);
}
这合法吗?
各种编译器输出各种错误。 Clang 是我心目中可读性最强的。它指出:
candidate template ignored: couldn't infer template argument 'O'
所以我猜我搞砸了签名,或者这不是 c++ 支持的功能。
我不知道有什么方法可以为 baked
的父 potato<T>
推断模板参数 T
。您可以使用 decltype(p.something)
知道 T
但这似乎无助于解决调用构造函数的问题。一种解决方法是更改 baked
的构造函数以采用任何 O
并假设它具有 something
:
struct baked {
template <class O>
baked(const O & p) : something(static_cast<T>(p.something))
{ }
baked() = default;
T something;
};
这会起作用,但它的类型安全性不如您的原始代码预期的那样。 that 问题的一种解决方法是引入 static_assert
检查 O
实际上是 potato<U>::baked
:
#include <type_traits>
template <class T>
struct potato {
struct baked {
template <class O>
baked(const O & p) : something(static_cast<T>(p.something))
{
using t_parent = potato<decltype(p.something)>;
static_assert(std::is_same<O, typename t_parent::baked>::value, "Not a baked potato!");
}
baked() = default;
T something;
};
template <class O>
potato(const potato<O>& p)
: mybaked(p.mybaked) {
}
potato() = default;
baked mybaked;
};
如果您尝试使用 something
传递任何其他内容,这应该可以很好地用于预期用途,但会失败并显示 "Not a baked potato!"。这会失败:
struct foo {
int something = 0;
};
int main(int, char**) {
foo bar;
potato<int>::baked baz(bar); // Error: Not a baked potato!
}
因为编译器的状态 O
不能从 const typename potato<O>::baked&
推导(在 ::
的左侧)。
您有几种解决方法:
将 baked
移到 parent 之外并使其成为模板:
// Possibly in namespace details
template <typename T>
struct baked_impl {
template <class O>
baked_impl(const typename baked_impl<O>& p)
: something(static_cast<T>(p.something)) {
}
baked_impl() = default;
T something;
};
template <class T>
struct potato {
using baked = baked_impl<T>;
// ...
};
在baked
中添加parent信息并使用SFINAE:
template <class T> struct potato;
// traits for SFINAE
template <class T> struct is_potato : std::false_type {};
template <class T> struct is_potato<potato<T>> : std::true_type {};
template <class T>
struct potato {
using value_type = T;
struct baked {
using parent = potato;
template <class O, std::enable_if_t<is_potato<typename O::parent>::value, int> = 0>
baked(const O& p)
: something(static_cast<typename O::parent::value_type>(p.something)) {
}
baked() = default;
T something;
};
// ...
};
我正在尝试编写可以推导出父 class 模板的嵌套 class 的 "promotion" 构造函数。它适用于父 class,但不适用于嵌套 class。这是一个代码示例。
template <class T>
struct potato {
struct baked {
template <class O>
baked(const typename potato<O>::baked& p)
: something(static_cast<T>(p.something)) {
}
baked() = default;
T something;
};
template <class O>
potato(const potato<O>& p)
: mybaked(p.mybaked) {
}
potato() = default;
baked mybaked;
};
int main(int, char**) {
potato<int> potato1;
potato<short> potato2(potato1);
}
这合法吗?
各种编译器输出各种错误。 Clang 是我心目中可读性最强的。它指出:
candidate template ignored: couldn't infer template argument 'O'
所以我猜我搞砸了签名,或者这不是 c++ 支持的功能。
我不知道有什么方法可以为 baked
的父 potato<T>
推断模板参数 T
。您可以使用 decltype(p.something)
知道 T
但这似乎无助于解决调用构造函数的问题。一种解决方法是更改 baked
的构造函数以采用任何 O
并假设它具有 something
:
struct baked {
template <class O>
baked(const O & p) : something(static_cast<T>(p.something))
{ }
baked() = default;
T something;
};
这会起作用,但它的类型安全性不如您的原始代码预期的那样。 that 问题的一种解决方法是引入 static_assert
检查 O
实际上是 potato<U>::baked
:
#include <type_traits>
template <class T>
struct potato {
struct baked {
template <class O>
baked(const O & p) : something(static_cast<T>(p.something))
{
using t_parent = potato<decltype(p.something)>;
static_assert(std::is_same<O, typename t_parent::baked>::value, "Not a baked potato!");
}
baked() = default;
T something;
};
template <class O>
potato(const potato<O>& p)
: mybaked(p.mybaked) {
}
potato() = default;
baked mybaked;
};
如果您尝试使用 something
传递任何其他内容,这应该可以很好地用于预期用途,但会失败并显示 "Not a baked potato!"。这会失败:
struct foo {
int something = 0;
};
int main(int, char**) {
foo bar;
potato<int>::baked baz(bar); // Error: Not a baked potato!
}
因为编译器的状态 O
不能从 const typename potato<O>::baked&
推导(在 ::
的左侧)。
您有几种解决方法:
将
baked
移到 parent 之外并使其成为模板:// Possibly in namespace details template <typename T> struct baked_impl { template <class O> baked_impl(const typename baked_impl<O>& p) : something(static_cast<T>(p.something)) { } baked_impl() = default; T something; }; template <class T> struct potato { using baked = baked_impl<T>; // ... };
在
baked
中添加parent信息并使用SFINAE:template <class T> struct potato; // traits for SFINAE template <class T> struct is_potato : std::false_type {}; template <class T> struct is_potato<potato<T>> : std::true_type {}; template <class T> struct potato { using value_type = T; struct baked { using parent = potato; template <class O, std::enable_if_t<is_potato<typename O::parent>::value, int> = 0> baked(const O& p) : something(static_cast<typename O::parent::value_type>(p.something)) { } baked() = default; T something; }; // ... };