Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/146.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在嵌套Lambda中使用'decltype'时,GCC Segfaults_C++_Lambda_G++_C++11 - Fatal编程技术网

C++ 在嵌套Lambda中使用'decltype'时,GCC Segfaults

C++ 在嵌套Lambda中使用'decltype'时,GCC Segfaults,c++,lambda,g++,c++11,C++,Lambda,G++,C++11,我创建了一个宏,可以方便地构建lambda函数,使用它我可以迭代我编写的库中的张量对象。然而,嵌套这些宏似乎会导致GCC出现内部分段错误。在扩展编译器的预处理器输出并经历一些尝试和错误后,我发现原因似乎是在类或结构的方法中声明的嵌套lambda函数的参数列表中使用了decltype。下面是一个使用标准库的简单示例 #include <iostream> #include <type_traits> template <class Iterator, class F

我创建了一个宏,可以方便地构建lambda函数,使用它我可以迭代我编写的库中的张量对象。然而,嵌套这些宏似乎会导致GCC出现内部分段错误。在扩展编译器的预处理器输出并经历一些尝试和错误后,我发现原因似乎是在类或结构的方法中声明的嵌套lambda函数的参数列表中使用了
decltype
。下面是一个使用标准库的简单示例

#include <iostream>
#include <type_traits>

template <class Iterator, class Func>
void for_each(const Iterator first, const Iterator last, Func func)
{
        for (Iterator it = first; it != last; ++it) {
                func(*it);
        }
}

template <class T>
class helper
{
        typedef typename T::size_type type;
};

template <class T>
class helper<T&>
{
        typedef typename T::size_type type;
};

template <class T>
class helper<T*>
{
        typedef typename T::size_type type;
};      

struct bar
{
        struct foo
        {
                typedef int size_type;
        } foo_;

        void test()
        {
                int arr[] = { 1, 2, 3 };
                for_each(arr, arr + 3, [&](int i) {
                        /*
                        ** XXX: The "typename ... type" segfaults g++!
                        */
                        for_each(arr, arr + 3, [&](typename helper<decltype(foo_)>::type j) {

                        });
                });
        }
};

int main()
{
        return 0;
}
#包括
#包括
模板
每个元素的void(常量迭代器优先,常量迭代器最后,Func Func)
{
for(迭代器it=first;it!=last;++it){
func(*it);
}
}
模板
类助手
{
typedef typename T::size_type type;
};
模板
类助手
{
typedef typename T::size_type type;
};
模板
类助手
{
typedef typename T::size_type type;
};      
结构条
{
结构foo
{
typedef int size_type;
}富奥;
无效测试()
{
int arr[]={1,2,3};
对于每个单元(arr、arr+3、[&](int i){
/*
**XXX:“typename…type”segg++!
*/
对于每个(arr,arr+3,[&](typename helper::type j){
});
});
}
};
int main()
{
返回0;
}
编译器输出:
$g++-Wall-std=c++0x嵌套\u lambda.cpp
嵌套的_lambda.cpp:在lambda函数中:
嵌套的_lambda.cpp:42:56:内部编译器错误:分段错误
请提交完整的bug报告,
如果合适,使用预处理源。
有关说明,请参阅。
预处理的源代码存储在/tmp/ccqYohFA.out文件中,请将其附加到bugreport中。
我最初选择使用
decltype
,因为一个对象被传递给一个宏,我需要提取对象的类型。根据对象的类型(
T
T&
T*
),我将使用traits类来提取
T::size\u type。
size\u type
将是lambda函数参数的类型


如何避免这个问题,而不必使用typedef预先声明lambda函数参数的类型?如果您能想到其他一些可以在宏中轻松实现的解决方案(即,在lambda函数的参数列表中重复复制和粘贴),这也会起作用。

对于那些可能遇到类似问题的人来说,这是一个非常粗糙的解决方法,我能想到的最好的标准解决方案是让宏预先声明一个typedef,将GUID-like前缀(我个人推荐
\u qki\u zbeu26\u w92b27bqy\u r62zf91j2n\u s0a02\u
)和
\u LINE\u
连接起来,为typedef名称生成一些华而不实的东西。幸运的是,这个名称不会与任何其他定义冲突

为了确保即使在lambda函数参数类型中使用了warbled名称时,也能连接相同的
\uuuuu行
,warbled名称需要由最初传递宏参数的宏生成,如下面的代码示例所示

#define _foo_GUID \
    _qki_zbeu26_w92b27bqy_r62zf91j2n_s0a02_

#define _foo_MANGLE_IMPL2(a, b) \
    a ## b

#define _foo_MANGLE_IMPL(a, b) \
    _foo_MANGLE_IMPL2(a, b)

#define _foo_MANGLE(a) \
    _foo_MANGLE_IMPL(_foo_GUID, a)

当把
\u foo\u MANGLE(\uu LINE\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu)作为宏参数传递时,请确保有一个额外的间接级别,以便
\u foo\u MANGLE(\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu,在编译器输出请求时提交完整的错误报告?通常,提交错误报告的一个好处是,阅读该报告的编译器工程师会就如何解决该问题提出建议。在不了解编译器内部结构的情况下,很难知道如何避免它。为什么这里需要typename<代码>助手::类型
没有依赖类型,因为您不在模板中;我习惯性地键入关键字。以两个下划线开头的名称(或一个下划线后跟大写字母)在用户代码中使用是非法的,因为它们是为实现保留的。谢谢,我更新了答案,以便宏符合标准。Hm?还有
\uuuu GUID
\uuu MANGLE\uimpl2
\uuu MANGLE\uimpl
\uu MANGLE
——所有这些都是非法的。另外(我之前没有提到)在全局范围中以下划线开头的任何名称都是保留的,所以
\u qki\u zbeu26\u w92b27bqy\u r62zf91j2n\u\u s0a02\u
仍然是一个问题。按名称来说,我以为您只是指声明的标识符。我知道有许多库声明以两个下划线开头的宏。不管怎么说,我又编辑了一次。很公平,只要它不用于在全局范围内声明真正的符号,因为它们将以
\u q
开头。(同样,以一个下划线开头,后跟一个大写字母的名称是保留的,无论其作用域如何,因此,
\u GUID
等仍然无法使用。)
#define _foo_GUID \
    _qki_zbeu26_w92b27bqy_r62zf91j2n_s0a02_

#define _foo_MANGLE_IMPL2(a, b) \
    a ## b

#define _foo_MANGLE_IMPL(a, b) \
    _foo_MANGLE_IMPL2(a, b)

#define _foo_MANGLE(a) \
    _foo_MANGLE_IMPL(_foo_GUID, a)