Во-первых, во втором примере Foo
не класс; это шаблон. Шаблоны генерируют такие вещи, как классы, функции и т. Д. c, но сам шаблон не тот, который он генерирует. Так что, если эта createMap
функция не принимает шаблон, а не специфицированный тип c, createMap<int, Foo>
- нонсенс для вашего второго случая.
Если вы создаете однородный контейнер, то каждое значение, которое хранит ваш контейнер должен быть того же типа. Таким образом, единственный способ для этого состоит в том, чтобы принудительно установить определенный тип c, либо тот, который стирает тип данной лямбды, либо тот, который применяет указанную сигнатуру c функции. Например, взяв указатель на функцию:
using FuncTySignature = int(); //Insert signature here.
using FuncTyPtr = FuncTySignature*;
struct Foo {
constexpr Foo(int a_, char const *b_, FuncTyPtr c_) : a(a_), b(b_), c(c_) {}
int a;
char const *b;
FuncTyPtr c;
};
Теперь Foo
больше не является шаблоном; он принимает указатель на функцию с заданной c сигнатурой.
Если вы должны заполнить эти функции лямбдами, а затем сделать их не захватывающими лямбда, используйте точную сигнатуру, указанную FuncTySignature
, и преобразуйте лямбду в указатель на функцию при ее применении. Например:
constexpr const auto map = createMap<int, Foo>({
{1, Foo{1234, "first", +[]() -> int {
return -1;
}}},
{2, Foo{5678, "second", +[]() -> int {
return -2;
}}},
});
-> int
просто для того, чтобы убедиться, что подпись совпадает. +
перед лямбда-выражением используется для провоцирования преобразования лямбда-функтора в указатель на лямбда-функцию.