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

Extract value from template argument's template argument

本文关键字:参数 提取      更新时间:2023-10-16

在下面的代码中:

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?

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的模板参数是一个类型(不是模板)。然后,该类型将作为参数提供给帮助程序,并与模板专用化进行匹配。由于类型填充了参数,因此专用化会提取它并返回它。

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{});
}

我想你可能想要这样的东西:

#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;
}