Извлечь значение из аргумента шаблона аргумента шаблона - PullRequest
1 голос
/ 09 июля 2019

В следующем коде:

template<auto A>
struct S{};

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

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

Я ожидаю, что он скомпилирует метод bar (), который просто вернет 1 Однако я получаю эти ошибки:

<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 ]

3 голосов
/ 09 июля 2019

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 голос
/ 09 июля 2019
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{});
}
0 голосов
/ 09 июля 2019

Я думаю, вы можете захотеть что-то вроде этого:

#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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...