Как правильно ссылаться на параметры, используя черты типа - PullRequest
3 голосов
/ 28 мая 2019

Я пытаюсь посчитать количество аргументов в переданной метке подписи шаблона.Я хочу знать количество аргументов, поскольку этот метод обернут в общую лямду, и в зависимости от количества переданных аргументов я добавлю немного больше информации к методу, переданному здесь.

Я выделилвопрос к фрагменту ниже.Приведенный ниже фрагмент работает, как и ожидалось, но как только я изменяю метод результата, чтобы получить ссылку на метод, он не компилируется.Почему ссылка на тип параметра влияет на тип?Как я могу заставить его работать со ссылкой?

Протестировано это с Microsoft Visual Studio 2017.

#include "pch.h"
#include <iostream>

template <typename Func>
struct func_traits;

template <typename R, typename... TArgs>
struct func_traits<R(*)(TArgs...)> {
    static constexpr uint32_t ARG_COUNT = sizeof...(TArgs);
};

class TestClass {
public:
    // Compile error!!!
    // error C2027: use of undefined type 'func_traits<METHOD>'
    // uint32_t Result(const METHOD& function)

    template <typename METHOD>
    uint32_t Result(const METHOD function) {
        return (func_traits< METHOD >::ARG_COUNT);
    }
};


void foo(int a, int b, int c)
{
}

int bar()
{
    return 0;
}

int baz(double)
{
    return 0;
}

int main()
{
    TestClass device;

    std::cout << device.Result(foo) << std::endl;
    std::cout << device.Result(bar) << std::endl;
    std::cout << device.Result(baz) << std::endl;
    return 0;

}

1 Ответ

0 голосов
/ 28 мая 2019

Сценарий в вашем примере очень редкий и связан с определенным правилом шаблона, связанным конкретно с функциями и массивом.

Для уточнения, если у вас есть шаблонная функция, которая берет другую функцию по ссылке, тогда тип, выведенный для T, является фактическим типом функции (не указателем на функцию). Например,

template<typename T>
void fun(const T& f);
{
.....
}
void print(int);
fun(print); //for this case T will be deduced as void(int) and not void(*)int i.e. T will not be a function pointer

Таким образом, чтобы ваш пример работал на эталонный пример, вам нужно создать еще одну специализацию шаблона, например:

template <typename R, typename... TArgs>
struct func_traits<R(TArgs...)> {
    static constexpr uint32_t ARG_COUNT = sizeof...(TArgs);
};  //note (*) is removed from template function

Короче говоря, если вы передаете функцию или массив по значению, они распадаются на указатель, но если вы передаете по ссылке, то они обрабатываются как есть. Более подробная информация доступна в Scott Meyers Effective Modern C ++ (https://www.oreilly.com/library/view/effective-modern-c/9781491908419/ch01.html)

...