我正在尝试编写嵌套类的“ promotion”构造函数,以推断出父类模板。它适用于父类,但不适用于嵌套类。这是一个代码示例。
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最易读。它指出:
候选模板被忽略:无法推断模板参数“ O”
所以我猜我要么弄乱了签名,要么这不是c ++支持的功能。
答案 0 :(得分:2)
我不知道为T
的父baked
推导模板参数potato<T>
的任何方法。您可以使用T
来了解decltype(p.something)
,但这似乎无助于解决调用构造函数的问题。一种解决方法是将baked
的构造函数更改为采用任何O
并假定它具有一个something
:
struct baked {
template <class O>
baked(const O & p) : something(static_cast<T>(p.something))
{ }
baked() = default;
T something;
};
这将起作用,但是它的类型安全性低于原始代码似乎想要的类型。解决该问题的一种方法是引入一个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
传递其他任何内容。这将失败:
struct foo {
int something = 0;
};
int main(int, char**) {
foo bar;
potato<int>::baked baz(bar); // Error: Not a baked potato!
}
答案 1 :(得分:1)
不能从O
(在const typename potato<O>::baked&
的左侧)推断出编译器::
的状态。
您有几种解决方法:
将baked
移到父级之外并使其成为模板:
// 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
中添加父信息并使用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;
};
// ...
};