C++ 嵌套模板结构

C++ nested templates structs

所以我对这样的代码有疑问:

我有这样的结构

template <int N>
struct Inner
{
    enum
    {
        val = 2*N
    };
};

我想达到这样的目的:

int v = Outer<Inner<4>>::val;
int b = Outer<false>::val;
cout<< v <<endl;
cout<< b <<endl;

我的目标是创建“Outer”结构,它采用 boolInner<int N> 并将 Outer::val 设置为 Inner::valbool 所以我创建了这样的东西(不工作):

template <bool B>
struct Outer
{
    enum
    {
        val = B
    };
};

template <Inner<int> I>
struct Outer
{
    enum
    {
        val = I::val
    };
};

这有什么问题以及如何解决? (我看过一些类似的问题,但仍然无法将其应用于我的问题)

您的代码中存在一些问题。

首先:你定义两个不同的Outer结构

template <bool B>
struct Outer
 { /* ... */ };

template <Inner<int> I>
struct Outer
 { /* ... */ };

而你不能。

如果需要,您可以声明一个 Outer 结构和两个 特化 ,但您必须决定 Outer 必须使用哪种类型的模板参数收到。

因为,看看你的需求,

int v = Outer<Inner<4>>::val;
int b = Outer<false>::val;

你想在一种情况下传递给它一个类型 (Inner<4>) 而在另一种情况下传递一个值。而你不能。

您必须决定 Outer 接收的是类型还是值。在C++17之前,如果接收到一个值,你必须决定这个值的类型;从 C++17 开始,您可以将 Outer 声明为接收泛型类型的值(auto 作为值的类型)。

问题:Inner<int> 的值不能是模板参数(但另请参阅 Michael Kenzel 的回答,它显示了基于模板值参数的可能的 C++20 解决方案)。

所以我看到的唯一解决方案(在 C++20 之前)是将 Outer 声明为接收类型

template <typename>
struct Outer;

然后你可以为 Inner 类型定义一个 Outer 特化

template <int N>
struct Outer<Inner<N>>
 { enum { val = Inner<N>::val }; }; // or simply enum { val = N };

对于 bool 值,您必须将它们包装在 class 中;我建议(从 C++11 开始)使用标准 class std::integral_constant 和以下 Outer 专业化

的定义
template <bool B>
struct Outer<std::integral_constant<bool, B>>
 { enum { val = B }; };

使用如下

int v = Outer<Inner<4>>::val;
int b = Outer<std::integral_constant<bool, false>>::val;

std::cout << v << std::endl;
std::cout << b << std::endl;

你也可以使用std::false_type定义b

int b = Outer<std::false_type>::val;

并且,从 C++17 开始,还有 std::bool_constant(shorthand for std::integral_constant for bool values)

int b = Outer<std::bool_constant<false>>::val;

模板参数可以是类型、值(非类型)或模板 [temp.param]。您要实现的目标需要您的模板 Outer 具有可以是类型或值的参数。不幸的是,这是不可能的。

你可以做的是将你的 bool 值包装在一个类型中:

template <bool b>
struct InnerBoolean
{
    static constexpr bool val = b;
};

然后对 Outer

有一个共同的定义
template <typename T>
struct Outer
{
    enum
    {
        value = T::val
    };
};

然后使用Outer<Inner<4>>Outer<InnerBoolean<False>>

与其编写自己的包装器,不如将 val 重命名为 value,则可以使用标准库在 std::bool_constantstd::true_type 中提供的包装器,并且std::false_type.

在 C++17 之前,非类型模板参数不能是 class 类型 [temp.param]/4, C++20 will lift this restriction and allow template parameters of any literal type。因此,只要 Inner 可以是文字类型,您就可以直接传递类型 Inner 的值并使用自动模板参数:

struct Inner
{
    int N;

    constexpr Inner(int N) : N(N) {}

    constexpr operator int() const { return 2*N; }
};

template <auto val>
struct Outer
{
    enum
    {
        value = val
    };
};

auto a = Outer<Inner(4)>::value;
auto c = Outer<false>::value;