застрял с метапрограммированием C ++ - PullRequest
0 голосов
/ 22 апреля 2020

Я пытаюсь попасть в TMP с книгой под названием Практическое метапрограммирование на C ++ , и я застрял при попытке получить один из первых примеров ...

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

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

I Не понимаю, почему это проблема, потому что сигнатура функции в выходных данных сборки кажется достаточно двусмысленной, чтобы идентифицировать типы аргументов со специализацией <Return(Args...)>. Я не понимаю, почему эта структура не будет сгенерирована с правильным членом using type = std::tuple<Args...>;, который, кажется, является ключом ко всему этому.

Вот и все:

#include <tuple>

// base template
template<typename Function>
struct makeTupleOfParams;

// template specialization to identify parameters
template <typename Return, typename... Params>
struct makeTupleOfParams<Return(Params...)>
{
    using type = std::tuple<Params...>;
};

// shortcut to identify type of parameters
template <typename Function>
using tupleOfParamTypes_t = typename makeTupleOfParams<Function>::type;

// function to unroll a tuple of parameters on a function
template <typename Function, typename Params, size_t... Index>
auto dispatchParams(Function f, Params p, std::index_sequence<Index...>)
{
    return f(std::get<Index>(p)...);
}

template <typename Function, typename... Params>
auto call(Function f, Params... p)
{
    // getting size of Params and argument types of Function
    constexpr size_t paramsCount = sizeof...(Params);
    tupleOfParamTypes_t<Function> params;

    return dispatchParams(f, params, std::make_index_sequence<paramsCount>());
}

auto f(int i, float j) -> decltype(i+j)
{
    return i + j;
};

void main()
{
    call(f, 1, 2.0);
}

И выход сборки:

1 > ------Build started : Project: TMP, Configuration : Debug Win32------
1 > main.cpp
1 > d:\git\meta - cpp - sandbox\src\main.cpp(40) : warning C4326 : return type of 'main' should be 'int' instead of 'void'
1 > d:\git\meta - cpp - sandbox\src\main.cpp(16) : error C2794 : 'type' : is not a member of any direct or indirect base class of 'makeTupleOfParams<Function>'
1 >     with
1 >     [
1 >         Function = float(__cdecl *)(int, float)
1 >     ]
1 > d:\git\meta - cpp - sandbox\src\main.cpp(28) : note: see reference to alias template instantiation 'tupleOfParamTypes_t<float(__cdecl *)(int,float)>' being compiled
1 > d:\git\meta - cpp - sandbox\src\main.cpp(41) : note: see reference to function template instantiation 'auto call<float(__cdecl *)(int,float),int,double>(Function,int,double)' being compiled
1 >     with
1 >     [
1 >         Function = float(__cdecl *)(int, float)
1 >     ]
1 > d:\git\meta - cpp - sandbox\src\main.cpp(26) : error C2938 : 'tupleOfParamTypes_t' : Failed to specialize alias template
1 > d:\git\meta - cpp - sandbox\src\main.cpp(31) : error C2672 : 'dispatchParams' : no matching overloaded function found
1 > d:\git\meta - cpp - sandbox\src\main.cpp(26) : error C2893 : Failed to specialize function template 'auto dispatchParams(Function,Params,std::integer_sequence<unsigned int,_Ix...>)'
1 > d:\git\meta - cpp - sandbox\src\main.cpp(26) : note: With the following template arguments :
1 > d:\git\meta - cpp - sandbox\src\main.cpp(26) : note: 'Function=float (__cdecl *)(int,float)'
1 > d:\git\meta - cpp - sandbox\src\main.cpp(26) : note: 'Params=unknown-type'
1 > d:\git\meta - cpp - sandbox\src\main.cpp(26) : note: 'Index={0, 1}'
1 > Done building project "TMP.vcxproj" --FAILED.
========== Build: 0 succeeded, 1 failed, 0 up - to - date, 0 skipped ==========

1 Ответ

1 голос
/ 22 апреля 2020

Когда вы вызываете функцию call, вы передаете функцию f в качестве аргумента. Однако c ++ неявно преобразует аргумент в указатель на функцию. Следовательно, при создании псевдонима типа параметр шаблона фактически равен int(*)(int,float), а не int(int,float). Поскольку это не соответствует требованиям частично специализированного шаблона, компилятор пытается создать псевдоним типа из неспециализированного шаблона для makeTupleOfParams. Однако несекретизированный шаблон не содержит псевдоним типа «тип», что приводит к ошибке компиляции.

Чтобы решить эту проблему, измените частично специализированный шаблон на:

template<typename Return, typename... Params>
struct makeTupleOfParams<Return(*)(Params...)> //pointer-to-function specialisation
{
    using type = std::tuple<Params...>;
};

Другим решением является использование type_traits для удаления черты указателя в функции call, например, так:

#include<type_traits>

template <typename Function, typename... Params>
auto call(Function f, Params... p)
{
    // getting size of Params and argument types of Function
    constexpr size_t paramsCount = sizeof...(Params);
    // modify function type to remove pointer trait
    tupleOfParamTypes_t<std::remove_pointer_t<Function>> params;

    return dispatchParams(f, params, std::make_index_sequence<paramsCount>());
}

В этом случае параметр шаблона, переданный в tupleOfParamTypes_t, будет int(int,float) .

...