Название более или менее говорит обо всем. У меня следующий бит кода:Может ли лямбда иметь связь «С»?
#include <vector>
#include <string>
#include <iterator>
#include <algorithm>
struct xloper12;
class Something
{
public:
std::string asString() const;
};
extern std::vector<Something> ourSomethings;
class ExcelOutputLoader
{
public:
void load(std::vector<std::string> const& value);
xloper12* asXloper() const;
};
extern xloper12* ProcessException(std::string const& functionName);
extern "C" __declspec(dllexport) xloper12*
getSomethingList()
{
try {
std::vector<std::string> results;
results.reserve(ourSomethings.size());
std::transform(
ourSomethings.begin(),
ourSomethings.end(),
std::back_inserter(results),
[](Something const& o) { return o.asString(); });
ExcelOutputLoader out;
out.load(results);
return out.asXloper();
} catch (...) {
return ProcessException("GetSomthing");
}
}
Я заменил большинство нестандартных заголовков с фиктивными деклараций; проблема заключается в последней функции (которая является , предназначенной для вызова из Excel). В основном, при компиляции с визуальной студией 2012, я получаю следующее предупреждение:
falseWarning.cc(34) : warning C4190: '<Unknown>' has C-linkage specified, but re
turns UDT 'std::basic_string<_Elem,_Traits,_Alloc>' which is incompatible with C
with
[
_Elem=char,
_Traits=std::char_traits<char>,
_Alloc=std::allocator<char>
]
(повторяются четыре раза, для хорошей меры). Но, как я понимаю, это, lambda определяет класс с членом operator()
, а не a функция. И (§7.5/4) «Связывание языка C игнорируется в , определяющем языковое связывание имен членов класса и типа функции функций члена класса». Что бы означало, что на лямбда следует игнорировать extern "C"
.
Это не большая вещь: это всего лишь предупреждение, и это легко работать вокруг (есть функция extern "C"
вызова функции C++, который делает фактическую работу). Но я все равно хотел бы знать: есть ли что-то фундаментальное, что я не понял о лямбда, или - это люди, разрабатывающие Visual C++, которые этого не понимают. (В последнем случае я волнуюсь. Поскольку переносимость не является проблемой , мы начали интенсивно использовать лямбда. Но если автору компилятора это не понятно, то я волнуюсь.)
EDIT:
Еще несколько тестов. Если я напишу что-то вроде:
extern "C" __declspec(dllexport) void
funct1()
{
extern std::string another();
}
Я также получаю предупреждение. На этот раз я бы сказал, что это правильно. another
- - функция в области пространства имен, и объявляется внутри блока extern "C"
, поэтому он должен иметь связь «C». (Интересно, я также получил предупреждение о том, что Возможно, я был укушен самой неприятной проблемой синтаксического анализа. extern
должно быть достаточно для компилятора, чтобы реализовать , что я не пытался определить локальный переменная)
с другой стороны, если я пишу что-то вроде:.
extern "C" __declspec(dllexport) void
funct2()
{
class Whatever
{
public:
std::string asString() { return std::string(); }
};
std::string x = Whatever().asString();
}
Там нет никакого предупреждения. В этом случае компилятор делает правильно игнорирует указанную связь «C» в функции-члене.
Который заставляет меня задаться вопросом немного. Является ли компилятор обработкой лямбда как класс с функцией operator()
(как это должно быть ), или это относится к ней как к функции? Похоже, что это последний, и это заставляет меня беспокоиться, если нет других тонких проблем, которые могут быть видимы только тогда, когда есть захват (и, вероятно, только в особых случаях).
Похож на ошибку компилятора для меня. Это 'getSomethingList', это' extern 'C ", и он не возвращает строку. Его спецификация привязки не должна относиться к деталям внутренней реализации. –
Я согласен с мнением, что это может быть ошибка VS. Вы пробовали на VS2013? – Pedrom
@IgorTandetnik Да и нет. Если я явно объявил функцию в 'extern 'C" или указатель на функцию, я бы ожидал, что они также будут 'extern' C". –