Перегрузка шаблонной функции той, которая принимает лямбды - PullRequest
0 голосов
/ 20 декабря 2018

Прошу прощения за прыжки здесь, но мой google-foo не подходит к функциям шаблонов (или шаблонам функций?) И их перегрузкам шаблонами функций (или шаблонами функций?).

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

Вот мой точный сценарий

template< typename buffer_t, typename value_t >
void fill(buffer_t buffer, const value_t value)
{
    std::fill(buffer.begin(), buffer.end(), value);
}

//partial specialization for buffers
template< typename sample_t, stride_t stride=1u >
void fill(Buffer<sample_t,stride> &buffer, const sample_t value)
{
    std::fill(buffer.begin(), buffer.end(), value);
}

//overload for filling a buffer with a callable
template< typename sample_t, stride_t stride=1u >
void fill(Buffer<sample_t,stride> buffer, const std::function<sample_t(size_t,size_t)> filler)
{
    const size_t N = buffer.samples();
    for(size_t i = 0; i < N; ++i) buffer[i] = filler(i, N);
}

А вот моя ошибка

ошибка: присвоение 'float' из несовместимого типа 'const (lambda at)' примечание: в экземпляре специализации шаблона функции 'Smule :: Audio :: fill, (lambda at)', запрашиваемой здесь fill (input, [] (size_t i, size_t N) {return (float) std :: sin (2.0 * M_PI * 4.0 * (double) i / (double) N);});

Ответы [ 2 ]

0 голосов
/ 21 декабря 2018

Насколько я могу судить, это невозможно.

Спасибо Игорю-Тандетнику за указание на то, что не существует такого понятия, как специализация шаблона функции;Есть только перегрузки функций.

Так что, когда дело доходит до этого, я пытаюсь перегрузить шаблон функции другим шаблоном функции с таким же количеством аргументов.Именно здесь шаблоны + разрешение перегрузки попадают в бермудский треугольник вычета / разрешения.https://en.cppreference.com/w/cpp/language/function_template#Function_template_overloading. Возможно в конце концов пройти, но предоставить кому-либо еще карту того, как вы туда попали, тоже довольно сложно, и удобство чтения кода + удобство обслуживания.

Лучший способ различить эти дваРеализация - это SFINAE и некоторые дополнительные черты типа, но C ++ 11 не предоставляет никаких черт типа для идентификации лямбда-выражений, что позволило бы мне самому определить класс черты. PW указал, что тип лямбды является объектом замыкания.Это делает определение класса черт типа для идентификации лямбда-выражений (или даже функторов произвольных аргументов) довольно сложной задачей.

Я пытался, но не получилось.В случае, если это кому-нибудь пригодится, я поделюсь тем, что попробовал.Может быть, кто-то еще может найти решение:

// Give myself a default-defined is_callable trait that is false_type
template< typename T, typename enable=void > struct is_callable: public std::false_type {};
//specializations for callable types:

// functors and lambdas
template< typename T, typename ...arg_t >
struct is_callable< decltype(T::operator(arg_t...)) >: public std::true_type {};

Опять же, это не сработало.Это ошибка компиляции, и я не совсем понял, можно ли вообще ссылаться на оператор с аргументами.Следующие перегрузки do , кажется, делают то, что я хочу ...

// functions
template< typename T >
struct is_callable< T, typename std::enable_if< std::is_function<T>::value >::type >: public std::true_type {};

// std::function
template< typename ret_t, typename ...arg_t >
struct is_callable< std::function<ret_t(arg_t...)> >: public std::true_type {};
0 голосов
/ 20 декабря 2018

Согласно [expr.prim.lambda] / 2 из стандартного черновика CPP,

Лямбда-выражение представляет собой prvalue , чей объект результатаназывается объектом замыкания.

Таким образом, когда вы передаете лямбда-аргумент в качестве аргумента, он принимается в качестве значения prvalue и выбирается следующая перегрузка:

template< typename buffer_t, typename value_t >
void fill(buffer_t buffer, const value_t value)

Но компиляция не удаласьпотому что lamdba присваивается float при создании экземпляра шаблона функции.

...