c++ - lambda 可以有 "C"链接吗?

标签 c++ visual-c++ c++11

标题或多或少说明了一切。我有以下内容 代码:

#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" );
    }
}

我已经将大部分非标准 header 替换为虚拟 header 声明;问题出在最后一个函数中(即 设计为从 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 语言链接在 确定类(class)成员姓名的语言联系 以及类成员函数的函数类型。”这将 意味着 extern "C" 应该在 lambda 上被忽略。

这不是什么大事:只是一个警告,而且很容易工作 周围(让 extern "C" 函数调用一个 C++ 函数,它 做实际工作)。但我还是想知道:有没有 我对 lambda 不了解的一些基本知识,或者 是开发Visual C++的人不懂吗。 (在后一种情况下,我很担心。因为可移植性不是 问题,我们已经开始大量使用 lambda。但如果 编译器的作者不懂,那我就担心了。)

编辑:

更多测试。如果我这样写:

extern "C" __declspec(dllexport) void
funct1()
{
    extern std::string another();
}

我也收到了警告。这一次,我会说它是正确的。 another 命名空间范围内的一个函数,它被声明 在 extern "C" block 中,所以它应该有 "C"链接。 (有趣的是,我还得到了一个警告,大意是 我可能被最棘手的解析问题困扰了。这 extern 应该足以让编译器实现 我并没有试图定义局部变量。)

另一方面,如果我这样写:

extern "C" __declspec(dllexport) void
funct2()
{
    class Whatever
    {
    public:
        std::string asString() { return std::string(); }
    };
    std::string x = Whatever().asString();
}

没有警告。在这种情况下,编译器会正确执行 忽略成员函数上指定的“C”链接。

这让我有点疑惑。编译器是否处理 lambda 作为一个带有 operator() 函数的类(因为它 应该),还是将其视为函数?看起来像那样 后者,这让我担心如果没有其他微妙的 涉及的问题,可能只有在捕获时才可见 (并且可能只有在非常特殊的情况下)。

最佳答案

这似乎未被标准指定。

5.1.2:

3 - [...] The closure type is declared in the smallest block scope, class scope, or namespace scope that contains the corresponding lambda-expression. [...]
5 - The closure type for a lambda-expression has a public inline function call operator [...]
6 - The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type's function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type's function call operator.

7.5:

4 - [...] In a linkage-specification, the specified language linkage applies to the function types of all function declarators, function names with external linkage, and variable names with external linkage declared within the linkage-specification. [...] A C language linkage is ignored in determining the language linkage of the names of class members and the function type of class member functions. [...]

因此,函数调用运算符或函数指针的转换函数都没有 C 语言链接,因为它们是类成员函数;但由于 5.1.2p6 没有指定转换函数返回的函数声明在何处,其类型可能有 C 语言链接。

一方面,如果我们考虑 7.5p4 中的示例:

extern "C" {
  class X {
  // ...
  void mf2(void(*)()); // the name of the function mf2 has C++ language
                       // linkage; the parameter has type pointer to
                       // C function
  };
}

这表明,只要 C 函数类型在转换声明的内联声明中或在 extern "C" block 中以其他方式声明,到函数指针的转换将返回指向 C 函数的类型指针:

extern "C" {
  class Y {
    (*operator void())(); // return type pointer to C function
  };
}

另一方面,要求函数具有与函数调用运算符相同的效果,如果C语言链接阻止它,这是不可能的;我们可以得出结论,该函数必须在 extern "C" block 之外声明,同样是转换函数的返回类型。但这可能会给编译器编写者带来额外的工作量。

关于c++ - lambda 可以有 "C"链接吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21000882/

相关文章:

c++ - 字符串不返回主函数

c++ - lambda 表达式的右值和左值引用 - gcc 与 msvc

c++ - 不允许嵌套函数,但为什么允许嵌套函数原型(prototype)? [C++]

c++ - 在不同线程中调用 std::function

c++ - InsertMenu/AppendMenu - 如何使用 C++ 和 win32 将图标添加到菜单和子菜单

c++ - OpenCV calibrateCamera() 断言失败

visual-c++ - Visual c++ OpenCV 2.1 contains()

c++11 - 如何在 Qt Creator 2.8.0 的通用项目中启用 C++11 支持?

c++ - 类类型的静态 constexpr 字段在 g++ 中给出链接时错误

java - CMake 构建在 Android Studio 中似乎不并行