Ошибка компиляции при использовании параметра шаблона класса в лямбде - PullRequest
3 голосов
/ 06 июля 2011

Я пытаюсь воссоздать поведение некоторых типов делегатов C # в C ++, и я сталкиваюсь с определенной ошибкой при компиляции - вот соответствующий код:

struct Nil { };

// Represents a C# Func
template <typename returnType = void,
          typename T1 = Nil,
          typename T2 = Nil,
          typename T3 = Nil>
class Func
{
public:
    vector<function<returnType(T1, T2, T3)>> _funcs;

    void operator+=(returnType (*functionPointerToAdd)(T1))
    {
        auto myFunc = [&] ( returnType (*functionPointerToAdd)(T1) )
                     -> returnType (*)(T1, T2, T3)
                     { functionPointerToAdd(T1); };
        // add myFunc to the vector of functions...
    }
};

То, что я пытаюсь сделать, это обернуть указатель на функцию в замыкании, чья сигнатура соответствует полному типу шаблона класса (эффективно «выбрасывая» значения, установленные в «Nil»). Я получаю ошибку:

error C2275: 'T1' : illegal use of this type as an expression

Я использую MSVC10, и я попытался typedef'ить переменные шаблона согласно Доступ к типу параметра шаблона класса внутри функции-члена с лямбда-ошибкой , но безрезультатно. Я понимаю, что есть несколько проблем с этой конкретной реализацией, с которыми я столкнусь в дальнейшем, но кроме этого мне просто интересно, почему я не могу использовать параметры шаблона класса в выражении lambda.

Ответы [ 2 ]

7 голосов
/ 06 июля 2011

Я думаю, что синтаксис 0x все еще немного испорчен.

auto myFunc = [&] ( returnType (*functionPointerToAdd)(T1) ) -> returnType (*)(T1, T2, T3) { functionPointerToAdd(T1); };

Эта строка - проблема. Давайте разберемся с этим:

auto myFunc = [&]

Это создает локальную переменную неопределенного типа, которая получает лямбду (что нормально) и запускает лямбду, которая принимает указатель на функцию по ссылке. Указатель уйдет, лучше сделайте его [=] для простоты (вы скопируете полный указатель больше - не важно).

( returnType (*functionPointerToAdd)(T1) ) 

Это аргументы в пользу лямбды. Это означает, что лямбда должна вызываться (!) С указателем на функцию типа returnType (*) (T1). Это не то, что вы хотите - вы хотите, чтобы он вызывался с T1, T2, T3.

-> returnType (*)(T1, T2, T3)

Это определяет тип возврата лямбды - и только это. Теперь вы говорите, что он должен возвращать указатель на функцию, которая возвращает returnType и принимает в качестве аргумента T1, T2 и T3. Тогда лямбда-тип будет

(returnType(*)(T1, T2, T3)) (*)(returnType(*)(T1))

, или функция, которая принимает указатель функции в качестве аргумента и возвращает указатель функции. Да, он слишком сложный и нечитаемый.

{ functionPointerToAdd(T1); };

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

Предложение по его исправлению (так как синтаксис ужасно сложен - надеюсь, приведенный выше текст поможет вам понять, почему я изменил:

auto myFunc = [=] ( T1 arg, T2, T3 ) -> returnType { return functionPointerToAdd(arg); }

Не стесняйтесь спрашивать, почему и как.

0 голосов
/ 06 июля 2011

Я думаю, что ошибка - именно то, что говорит компилятор: ваш вызов functionPointerToAdd(T1) не имеет смысла.T1 это тип, а не переменная.Ваша лямбда принимает в качестве аргумента только указатель на функцию, но нет действительного объекта для вызова функции!

Кроме того, что должна возвращать лямбда?Если его единственная цель - вернуть functionPointerToAdd(...), не должен ли его тип возврата просто быть returnType?

Может быть что-то вроде этого (но я не полностью понимаю ваши требования):

typedef returnType (*myFP)(T1);

auto myFunc = [] (myFP f, const T1 & t) -> returnType { return f(t); };

Я также избавляюсь от «захвата всего по ссылке» ([&]), потому что вы, кажется, не используете нелокальные переменные.

Редактировать: Ой, подождите, я вижу, вы хотите добавить myFunc к вектору.Таким образом, вы хотите привязать данный указатель к лямбде, тело которого состоит из вызова функции.Хорошо, давайте посмотрим:

void operator+=(myFP f)
{
  auto myFunc = [f] (T1 t, T2, T3) -> returnType { return f(t); };
  the_vector.push_back(myFunc);
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...