使用可变参数模板的静态继承
Static inheritance with variadic templates
我正在尝试使用 std::conditional
来实现静态继承。
我的 child
class、parent_one
和 parent_two
有两个可能的父级,它们应该根据传递的类型保存多个变量,而 parent_two
有两种类型。我正在使用标签分派来区分我想继承的 classes。
现在进入正题。当我调用 child
并将其标记为从 parent_one
继承两种类型时,它按预期工作。但是,如果我试图将任意数量的类型传递到 child
并打算从 parent_one
继承,我会收到错误消息:
static_polymorphism.cpp: In instantiation of ‘class child<foo_type, int, int, double, float>’:
static_polymorphism.cpp:110:41: required from here
static_polymorphism.cpp:99:7: error: wrong number of template arguments (4, should be 2)
99 | class child : public std::conditional_t<
| ^~~~~
static_polymorphism.cpp:90:7: note: provided for ‘template<class T, class F> class parent_two’
90 | class parent_two {
| ^~~~~~~~~~
static_polymorphism.cpp: In function ‘int main(int, char**)’:
static_polymorphism.cpp:111:9: error: ‘class child<foo_type, int, int, double, float>’ has no member named ‘log’
111 | first.log();
如果我理解正确,编译器应该根据我的标签分派生成代码。这意味着它应该创建重载的 classes - N(基于传递的类型)来自 parent_one
和 M(也基于传递的类型)来自 parent_two
。但是出于某种我不知道的原因,它不接受类型的变量计数。你能告诉我我做错了什么吗?
实现在这里。
using one_t = struct foo_type{};
using two_t = struct bar_type{};
template <typename ... TYPES>
class parent_one {
public:
parent_one() = default;
void log() {
std::cout << "parent_one" << std::endl;
}
};
template <typename T, typename F>
class parent_two {
public:
parent_two() = default;
void log() {
std::cout << "parent_two" << std::endl;
}
};
template <typename T, typename ... ARGS>
class child : public std::conditional_t<
std::is_same_v<T, one_t>,
parent_one<ARGS...>,
parent_two<ARGS...>
>
{
public:
child() = default;
};
int main(int argc, char *argv[]) {
child<one_t, int, int, double, float> first;
first.log();
child<two_t, int, int> second;
second.log();
return 0;
}
std::conditional_t<
std::is_same_v<T, one_t>,
parent_one<ARGS...>,
parent_two<ARGS...>
>
此处在检查条件之前验证了两个备选方案。 std::conditional_t
并不神奇,只是一个常规模板,它要求所有模板参数都有效才能执行任何操作。
您需要延迟将模板参数替换到父模板中,直到选择了其中一个替代项。这是一种可能的解决方案:
template <template <typename...> typename T>
struct delay
{
template <typename ...P>
using type = T<P...>;
};
// ...
class child :
public std::conditional_t<
std::is_same_v<T, one_t>,
delay<parent_one>,
delay<parent_two>
>::template type<ARGS...>
{
// ...
};
你可能是经典:
template<class T, class... Args> struct child: parent_one<Args...> {};
template<class T, class A, class B> struct child<T, A, B>: parent_two<A, B> {};
template<class A, class B> struct child<one_t, A, B>: parent_one<A, B> {};
(两个专业可以通过requires (!std::is_same_v<T, one_t>)
合二为一)。
我正在尝试使用 std::conditional
来实现静态继承。
我的 child
class、parent_one
和 parent_two
有两个可能的父级,它们应该根据传递的类型保存多个变量,而 parent_two
有两种类型。我正在使用标签分派来区分我想继承的 classes。
现在进入正题。当我调用 child
并将其标记为从 parent_one
继承两种类型时,它按预期工作。但是,如果我试图将任意数量的类型传递到 child
并打算从 parent_one
继承,我会收到错误消息:
static_polymorphism.cpp: In instantiation of ‘class child<foo_type, int, int, double, float>’:
static_polymorphism.cpp:110:41: required from here
static_polymorphism.cpp:99:7: error: wrong number of template arguments (4, should be 2)
99 | class child : public std::conditional_t<
| ^~~~~
static_polymorphism.cpp:90:7: note: provided for ‘template<class T, class F> class parent_two’
90 | class parent_two {
| ^~~~~~~~~~
static_polymorphism.cpp: In function ‘int main(int, char**)’:
static_polymorphism.cpp:111:9: error: ‘class child<foo_type, int, int, double, float>’ has no member named ‘log’
111 | first.log();
如果我理解正确,编译器应该根据我的标签分派生成代码。这意味着它应该创建重载的 classes - N(基于传递的类型)来自 parent_one
和 M(也基于传递的类型)来自 parent_two
。但是出于某种我不知道的原因,它不接受类型的变量计数。你能告诉我我做错了什么吗?
实现在这里。
using one_t = struct foo_type{};
using two_t = struct bar_type{};
template <typename ... TYPES>
class parent_one {
public:
parent_one() = default;
void log() {
std::cout << "parent_one" << std::endl;
}
};
template <typename T, typename F>
class parent_two {
public:
parent_two() = default;
void log() {
std::cout << "parent_two" << std::endl;
}
};
template <typename T, typename ... ARGS>
class child : public std::conditional_t<
std::is_same_v<T, one_t>,
parent_one<ARGS...>,
parent_two<ARGS...>
>
{
public:
child() = default;
};
int main(int argc, char *argv[]) {
child<one_t, int, int, double, float> first;
first.log();
child<two_t, int, int> second;
second.log();
return 0;
}
std::conditional_t<
std::is_same_v<T, one_t>,
parent_one<ARGS...>,
parent_two<ARGS...>
>
此处在检查条件之前验证了两个备选方案。 std::conditional_t
并不神奇,只是一个常规模板,它要求所有模板参数都有效才能执行任何操作。
您需要延迟将模板参数替换到父模板中,直到选择了其中一个替代项。这是一种可能的解决方案:
template <template <typename...> typename T>
struct delay
{
template <typename ...P>
using type = T<P...>;
};
// ...
class child :
public std::conditional_t<
std::is_same_v<T, one_t>,
delay<parent_one>,
delay<parent_two>
>::template type<ARGS...>
{
// ...
};
你可能是经典:
template<class T, class... Args> struct child: parent_one<Args...> {};
template<class T, class A, class B> struct child<T, A, B>: parent_two<A, B> {};
template<class A, class B> struct child<one_t, A, B>: parent_one<A, B> {};
(两个专业可以通过requires (!std::is_same_v<T, one_t>)
合二为一)。