2013-06-25 3 views
4

Я пытаюсь моим C++ 11 кода, чтобы увидеть, если весь последний важный компилятор поддерживает функцию, которые я использовал, и следующий укороченный кодClang не позволяет static_cast к родительскому классу с шаблоном, в то время как г ++ и ККА позволяют

#include <valarray> 

struct T 
{ 
    double vv[3]; 
}; 

class V : public std::valarray<T> 
{ 
    public: 
     auto begin()->decltype(std::begin(static_cast<std::valarray<T>>(*this))) 
     { 
      return std::begin(static_cast<std::valarray<T>>(*this)); 
     } 
}; 

int main(void) 
{ 

} 

будет скомпилирован с g ++ 4.8.1 (из репозитория Debian sid), компилятор Intel C++ 13.1.1 20130313, но не Clang 3.3-2 (из репозитория sid sid).

Данная ошибка:

test.cpp:11:73: error: no viable conversion from 'V' to 'std::valarray<T>' 
    auto begin()->decltype(std::begin(static_cast<std::valarray<T>>(*this))) 
                    ^~~~~ 

Однако подобный код

namespace std 
{ 
auto begin(V& vv) -> decltype(std::begin(static_cast<V::parent_t>(vv))) 
{ 
    return std::begin(static_cast<V::parent_t>(vv)); 
} 
} 

будет составлять все три компиляторов.

Мой вопрос: это сам код, разрешенный стандартом языка, только Кланг неправильно скомпилировал его или поддерживается только g ++/icc? Или это неопределенное поведение?

+1

Я думаю (но не уверен), что V не является полным в деклараторах (включая возвращаемый возвращаемый тип) его членов, поэтому static_cast его базовому классу там не допускается, так как для этого потребуется полный тип. Я более уверен в том, что он не является полным тогда, что это запрещает актерский состав. –

+1

Что-то, что вы можете попробовать вместо этого: '* static_cast *> (this)' –

+0

или просто использовать 'decltype (begin (valarray ()))' –

ответ

0

Код очень опасный и должен быть исправлен даже для GCC и ICC.

Вы используете static_cast для значения типа, а не ссылки или указателя. Это создает новый временный объект valarray, поэтому вызывается перегрузка begin (вероятно, не то, что вы намеревались), и итератор, возвращаемый begin(), ссылается на временное, которое выходит за пределы области действия немедленно, поэтому возвращенный итератор недействителен и разыменовывает его это неопределенное поведение.

код будет компилироваться, как это:

auto begin()->decltype(std::begin(std::declval<std::valarray<T>&>())) 
    { 
     return std::begin(static_cast<std::valarray<T>&>(*this)); 
     /* cast to reference type! ^^^^^^^^^^^^^^^^^ */ 
    } 

decltype не нужно отбрасывать this, это просто необходимо знать тип вызова std::begin на valarray<T>, так что это, если не имеет значения тип является неполным, потому что вам не нужен листинг.

В теле функции тип считается полным в любом случае, поэтому актер действует.