gpt4 book ai didi

c++ - 推断/删除模板模板参数的类型

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:06:53 29 4
gpt4 key购买 nike

当使用模板模板参数时,我如何推断或删除模板模板的模板类型?

考虑以下 SSCCE:

#include <cstdint>
#include <cstddef>
#include <iostream>
using namespace std;

template<int i>
struct Value { };

template<int i>
struct BadValue { };

template<typename... G>
struct Print;

template<template<int> class ValueType, int... Is>
struct Print< ValueType<Is>... > {
static void print() {
const int is[] = { Is... };
for (int i: is)
cout << i;
cout << endl;
}

};

using V1 = Value<1>;
using V2 = Value<2>;
using V3 = Value<3>;
using BV = BadValue<1>;

int main() {
Print<V2, V1, V2, V3>::print(); // <-- fine
Print<V2, V1, V2, BV>::print(); // <-- BV used by accident
}

推导 template<int> class ValueType Print 的参数类到模板类,如 ValueBadValue classes 强制将参数包中的所有模板参数打包到 Print类是相同的特化 ValueType模板类——这是故意的。即 main() 中的第二行函数导致编译时错误 ValueType无法推断参数同时匹配 ValueBadValue类。如果用户在使用 Print 时不小心尝试混合模板模板出现编译时错误,这提供了一些诊断。

然而,上面的实现仍然有 int ValueType 的内部模板参数的固定类型模板模板参数。我怎样才能删除它并推导它呢?

一般来说,在推导模板模板参数时,如何访问内部模板参数?

最佳答案

如果我没理解错的话,你想要那个Print<V2, V1, V2, VB>::print();生成一个更容易理解的错误。

为此,我能想到的最好的方法是使用 static_assert()

在这种特殊情况下——Printstruct只实现了部分特化而没有实现通用版本——一个不是真正但简单的解决方案可用:实现通用版本以提供 static_assert()您选择的消息出错。

举例

template <typename ... G>
struct Print
{
static_assert( sizeof...(G) == 0, "not same int container for Print<>");

static void print()
{ };
};

template <template<int> class ValueType, int ... Is>
struct Print< ValueType<Is>... >
{
static void print()
{
using unused = int const [];

(void)unused { (std::cout << Is, 0)... };

std::cout << std::endl;
}
};

不幸的是,这个解决方案被接受为有效 Print<> ;不知道对你有没有好处。

另一个(更好,恕我直言,但更详细)解决方案可以转换 Print接受可变参数的特化的部分特化 int容器(可变的 ValueTypes 而不是固定的 ValueType )并且在 static_assert() 中,检查(使用自定义类型特征)所有容器是否相同。

再见,具有以下自定义类型特征

template <template <int> class ...>
struct sameCnts : public std::false_type
{ };

template <template <int> class C0>
struct sameCnts<C0> : public std::true_type
{ };

template <template <int> class C0, template <int> class ... Cs>
struct sameCnts<C0, C0, Cs...> : public sameCnts<C0, Cs...>
{ };

你可以写Print特化如下

template <template <int> class ... Cs, int ... Is>
struct Print< Cs<Is>... >
{
static_assert(sameCnts<Cs...>{}, "different containers in Print<>");

static void print()
{
using unused = int const [];

(void)unused { (std::cout << Is, 0)... };

std::cout << std::endl;
}
};

如果会用C++17,就可以用folding,可以写type traits

template <template <int> class, template <int> class>
struct sameCnt : public std::false_type
{ };

template <template <int> class C>
struct sameCnt<C, C> : public std::true_type
{ };

template <template <int> class C0, template <int> class ... Cs>
struct sameCnts
: public std::bool_constant<(sameCnt<C0, Cs>::value && ...)>
{ };

和(也在 print() 方法中使用折叠)Print如下

template <template <int> class ... Cs, int ... Is>
struct Print< Cs<Is>... >
{
static_assert( sameCnts<Cs...>{}, "different containers in Print<>");

static void print()
{ (std::cout << ... << Is) << std::endl; }
};

-- 编辑 --

OP 询问

But how can I have the Print class accept also, for example, types that are specialized for a double non-type value instead of the int non-type values?

不确定你想要什么但是(记住 double 值不能是模板非类型参数)我想你想要一个 Print当此非类型模板参数的类型未像您的示例中那样固定时接受具有非类型模板参数的类型(int)。

对于 C++11 和 C++14,我认为有必要显式显示非类型值的类型。

我的意思是……如果你写Print如下

template <typename ...>
struct Print;

template <typename T, template <T> class ... Cs, T ... Is>
struct Print< T, Cs<Is>... >
{
static_assert(sameCnts<Cs...>{}, "different containers in Print<>");

// ...
};

你必须这样使用它

Print<int, V2, V1, V2, V3>::print();

那是解释int (或 long 或其他)作为第一个模板参数。这是因为 int无法推断出类型。

从 C++17 开始,您可以使用 auto作为非类型模板参数的类型,所以你可以写 Print如下

template <typename ...>
struct Print;

template <template <auto> class ... Cs, auto ... Is>
struct Print< Cs<Is>... >
{
static_assert( sameCnts<Cs...>{}, "different containers in Print<>");

static void print()
{ (std::cout << ... << Is) << std::endl; }
};

而且不需要明确类型,你可以写

Print<V2, V1, V2, V3>::print();

在这种情况下,您必须使用 auto而不是 int也在 sameCntsameCnts .

关于c++ - 推断/删除模板模板参数的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48490322/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com