Сегфиксы GCC при использовании `decltype` во вложенной лямбде - PullRequest
9 голосов
/ 27 января 2012

Я создал макрос, который удобно строит лямбда-функции, используя которые я могу перебирать тензорные объекты в библиотеке, которую я написал. Однако вложение этих макросов, по-видимому, приводило к тому, что GCC подвергался внутренней ошибке сегментации. Расширив выходные данные препроцессора компилятора и пройдя через метод проб и ошибок, я обнаружил, что причиной, по-видимому, является использование 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;
}

Выход компилятора:

$ g++ -Wall -std=c++0x nested_lambda.cpp
nested_lambda.cpp: In lambda function:
nested_lambda.cpp:42:56: internal compiler error: Segmentation fault
Please submit a full bug report,
with preprocessed source if appropriate.
See <file:///usr/share/doc/gcc-4.6/README.Bugs> for instructions.
Preprocessed source stored into /tmp/ccqYohFA.out file, please attach this to your bugreport.

Сначала я решил использовать decltype, потому что объект передается макросу, и мне нужно извлечь тип объекта. Исходя из типа объекта (T, T& или T*), я использовал бы класс черт, чтобы T::size_type. size_type был бы тогда типом параметров лямбда-функции.

Как можно обойти эту проблему, не используя typedef для предварительного объявления типа параметра функции лямбда? Если вы можете подумать о каком-то другом решении, которое можно легко реализовать в макросе (то есть, многократно копировать и вставлять в список параметров лямбда-функции), это тоже сработает.

Ответы [ 2 ]

1 голос
/ 27 января 2012

В качестве очень грубого обходного пути для тех, кто может столкнуться с подобными проблемами, лучшее стандартное решение, которое я мог придумать, заключалось в том, чтобы макрос заранее объявлял typedef, объединяя GUID-подобный префикс (я лично рекомендую _qki_zbeu26_w92b27bqy_r62zf91j2n_s0a02_) и__LINE__ для создания бессмысленной чепухи для имени typedef.Если повезет, это имя не будет конфликтовать с любыми другими определениями.

Чтобы гарантировать, что тот же самый __LINE__ будет объединен, даже когда имя типа «warbled» используется для типов параметров лямбда-функции, имя «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)

При передаче _foo_MANGLE(__LINE__) в качестве параметра макроса, пожалуйста, убедитесь, что существует дополнительный уровень косвенности, так_foo_MANGLE(__LINE__) оценивается перед использованием.

0 голосов
/ 24 августа 2012

Эта ошибка в настоящее время устранена , и я думаю, что она должна быть исправлена ​​в ближайшее время.

...