Название более или менее говорит обо всем. У меня есть следующий бит кода:
#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). В основном, когда скомпилировано с Visual Studios 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()
, а не
функция. И (§7.5/4) "Связывание языка C игнорируется в
определение языковой связи имен членов класса
и тип функции функций-членов класса.
означает, что extern "C"
следует игнорировать на лямбда.
Это не большая вещь: это только предупреждение, и это легко работать
(функция extern "C"
вызывает функцию С++, которая
делает фактическую работу). Но я все равно хотел бы знать: есть ли
что-то фундаментальное, что я не понял о лямбда, или
это люди, разрабатывающие Visual С++, которые этого не понимают.
(В последнем случае я беспокоюсь. Поскольку переносимость не является
вопрос, мы начали интенсивно использовать лямбда. Но если
автор компилятора не понимает этого, тогда я волнуюсь.)
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()
(так как она
должен), или он рассматривает его как функцию? Похоже, что
последнее, и это заставляет меня беспокоиться, если нет других тонких
проблемы, вероятно, видимые только при захвате
(и, вероятно, только в особых случаях).