从模板参数的模板参数中提取值

时间:2019-07-09 13:19:09

标签: c++ templates c++17

在以下代码中:

template<auto A>
struct S{};

template<template <auto A> class H>
auto foo(){
    return A;
}

auto bar(){
    return foo<S<1>>(); // should return 1
}

我希望它会编译一个只返回1的bar()方法。 但是我得到这些错误:

<source>: In function 'auto foo()':
<source>:15:12: error: 'A' was not declared in this scope
   15 |     return A;
      |            ^
<source>: In function 'void bar()':
<source>:19:15: error: no matching function for call to 'foo<S<1> >()'
   19 |     foo<S<1>>();
      |               ^
<source>:14:6: note: candidate: 'template<template<auto A> class H> auto foo()'
   14 | auto foo(){
      |      ^~~
<source>:14:6: note:   template argument deduction/substitution failed:

有什么方法可以实际获得值A?

3 个答案:

答案 0 :(得分:3)

A未指定存在的内容。 foo的参数是模板,而不是专门化的参数。加以区别很重要,因为这就是为什么在传递S<1>时会出现不匹配错误的原因,正确的参数是foo<S>

S<1>是一个特殊化,它填充了丢失的位(自变量)。但是H不是特殊化,它是模板本身,没有自变量。 A除了要填充的东西之外没有别的了,它还不存在,所以您不能使用它。

要获得所需的内容,需要部分模板专门化。这不适用于功能模板,但是我们可以通过转发给类模板的成员来解决它。像这样:

template<auto A>
struct S{};

template<typename> struct foo_helper;

template<template <auto> class H, auto A>
struct foo_helper<H<A>> {
    static auto run() { return A; }
};

template<class H>
auto foo(){
    return foo_helper<H>::run();
}

auto bar(){
    return foo<S<1>>(); // should return 1
}

现在foo的模板参数是一种类型(不是模板)。然后,将该类型作为参数提供给助手,并与模板专门化进行匹配。由于该类型已填充参数,因此专业化将其提取并返回。

答案 1 :(得分:1)

template<template <auto A> class H>
auto foo(){
    return A;
}

定义一个采用模板而不是专门化的函数。这意味着您需要像foo<S>()那样称呼它,因为S是一个模板,而不是foo<S<1>>(),因为S<1>是一个专业。

您可以做的一件事是将foo更改为

template<template <auto> class H, auto A>
auto foo(){
    return A;
}

然后您可以像使用它

foo<S, 1>()

然后让foo使用模板S并具有要使用的值(在这种情况下为1)。

如果您希望foo<S<1>>()返回1,则可以添加一个辅助函数并将foo更改为以下内容

template<template <auto> class T, auto V>
constexpr auto get_value(T<V>)
{
    return V;
}

template<typename T>
auto foo(){
    return get_value(T{});
}

答案 2 :(得分:0)

我认为您可能想要这样的东西:

#include <iostream>

template<auto A_val>
struct S {
    static constexpr auto A = A_val;
    static constexpr auto v = 2;
};


template<class H>
auto foo(){
    return H::A;
}

auto bar(){
    return foo<S<1>>();
}

int main()
{
    std::cout << bar() << std::endl;  // Prints "1"
    return 0;
}