Я использую идиому c ++, который позволяет определить общее поведение (GeneralFunction
), которое настраивается путем вызова определенных функций (SpecificFunction
) - переключения между ними по классам тегов (к сожалению, я забыл названиеидиома).
Я решил, что хотел, чтобы SpecificFunctions имели произвольный тип возврата.Но так как мы находимся в c ++, мне нужно объявить идентификатор заранее, прежде чем упомянуть его в GeneralFunction
.
Здесь я надеюсь, что я объявляю шаблон SpecificFunction, который при его создании будет объявлением, соответствующим конкретной перегрузке SpecificFunction, которая будет определена ниже:
#include <utility>
#include <iostream>
template <typename Tag, typename ... Args>
struct ReturnTypeTrick;
template <typename Tag, typename ... Args>
inline auto SpecificFunction(Tag, Args&& ... args) -> typename ReturnTypeTrick<Tag, Args...>::type; // basically saying SpecificFunction returns what it returns
тип возвращаемого значения неизвестендо реализации, но это не должно иметь значения сейчасМне просто нужно объявить идентификатор, чтобы я мог использовать его в GeneralFunction
template <typename Tag, typename ... Args>
struct ReturnTypeTrick {
using type = decltype(SpecificFunction(Tag(), std::declval<Args>() ...));
};
Общая функция с общим поведением:
template <typename Tag, typename ... Args>
inline auto GeneralFunction (Args&& ... specific_args) {
// do something common for all implementations
// this is where the behavior differs
return SpecificFunction(Tag(), std::forward<Args>(specific_args) ...);
}
Реализация по умолчанию для SpecificFunction Я решилпредоставить:
template <typename Tag, typename ... Args>
inline bool SpecificFunction(Tag, Args&& ...) { // default implementation
return false;
}
определение определенных функций поведения:
struct Algorithm1 {};
inline auto SpecificFunction(Algorithm1, int param1, char param2) {
return 10;
}
struct Algorithm2 {};
inline auto SpecificFunction(Algorithm2, long param1) {
return "y";
}
struct Algorithm3 {};
int main() {
std::cout << GeneralFunction<Algorithm1>(1, 'a') << std::endl;
std::cout << GeneralFunction<Algorithm2>(1l) << std::endl;
/* these somehow work, probably independently on the
`SpecificFunction` declaration above because my compiler is OK with
functions not being declared at all. BUT changing these simple
SpecificFunction definitions into templates – that is line in
GeneralFunction would look like
return SpecificFunction<SomeTemplateArg>(Tag(), std::forward<Args>(specific_args) ...);
– and removing the declaration results in undeclared indentifier
`SpecificFunction`, so I need to be able to declare it */
std::cout << GeneralFunction<Algorithm3>("wtf this should call the // default implementation") << std::endl;
// error: call to 'SpecificFunction' is ambiguous
static_assert(std::is_same_v<typename ReturnTypeTrick<Algorithm3, const char*>::type, bool>, "the return type of the generated declaration is correct if you don't see this message");
return 0;
}
Сообщение об ошибке:
/scratch_2.cpp:22:12: error: call to 'SpecificFunction' is ambiguous
return SpecificFunction(Tag(), std::forward<Args>(specific_args) ...);
^~~~~~~~~~~~~~~~
/scratch_2.cpp:51:18: note: in instantiation of function template
specialization 'GeneralFunction<Algorithm3, char const (&)[52]>' requested here
std::cout << GeneralFunction<Algorithm3>("wtf this should call the // default implementation") << std::endl;
^
/scratch_2.cpp:8:13: note: candidate function [with Tag = Algorithm3, Args
= <char const (&)[52]>]
inline auto SpecificFunction(Tag, Args&& ... args) -> typename ReturnTypeTrick<Tag, Args...>::type; // basically saying Spe...
^
/scratch_2.cpp:26:7: note: candidate function [with Tag = Algorithm3, Args
= <char const (&)[52]>]
inline bool SpecificFunction(Tag, Args&& ...) { // default implementation
Кажется, оно не может сопоставить сгенерированное объявление с определениемреализация по умолчанию SpecificFunction
.
Вы можете видеть, что сгенерированное объявление является тем же (они называют это ошибкой: неоднозначным) как заголовок определения.Это забавно, потому что это именно та вещь - та идентичность, на основе которой я думал, что объявление и определение были спарены.
Также я попытался изменить заголовок // default implementation
SpecificFunction на
template <typename Tag>
inline bool SpecificFunction(Tag, ...) { // default implementation
return false;
}
но вместо этого я получаю ошибку компоновщика:
Undefined symbols for architecture x86_64:
"ReturnTypeTrick<Algorithm3, char const (&) [52]>::type SpecificFunction<Algorithm3, char const (&) [52]>(Algorithm3, char const (&&&) [52])", referenced from:
auto GeneralFunction<Algorithm3, char const (&) [52]>(char const (&&&) [52]) in scratch_2-b3bb4f.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)