2015-02-07 2 views
2

Я вижу странную ошибку от Clang (3.4 и 3.5), когда пытаюсь скомпилировать этот код C++ 14, который использует шаблон переменной лямбда-типа.Тип вызываемого объекта 'auto' не является указателем функции или функции

Here's the C++14 code as I'd like to write it.

Here's a second version, с некоторыми из библиотеки _t и _v вещей удалены, чтобы сделать компилятор счастливого:

#include <type_traits> 

template <class T> 
class forward_if_wrapper { 

    template <class U, class Enable = typename std::enable_if<std::is_lvalue_reference<U>::value>::type> 
    static U forward(U&& u) { 
     return u; 
    } 

    template <class U, class Enable = typename std::enable_if<!std::is_lvalue_reference<U>::value>::type> 
    static U&& forward(U&& t) { 
     return static_cast<U&&>(t); 
    } 
}; 
auto forward = [](auto&& t) { return forward_if_wrapper<decltype(t)>::forward(t); }; 
template <class T> auto forward_if = [](auto&& u) { return forward_if_wrapper<T>::forward(u); }; 

// -------- 

#include <stdio.h> 
#include <vector> 

template<class Elt> 
void bar(Elt&& e) { 
    printf("Called %s\n", __PRETTY_FUNCTION__); 
} 

template<class Container> 
void foo(Container&& c) { 
    for (auto&& elt : c) { 
     bar(forward_if<Container>(elt)); 
    } 
} 

int main() { 
    std::vector<int> v = {1,2}; 
    foo(v); 
    foo(std::move(v)); 
} 

ошибкой я вижу из второго кода с Clang является:

test.cc:34:13: error: called object type 'auto' is not a function or function pointer 
     bar(forward_if<Container>(elt)); 
      ^~~~~~~~~~~~~~~~~~~~~~~ 
test.cc:43:5: note: in instantiation of function template specialization 'foo<std::__1::vector<int, std::__1::allocator<int> > &>' requested here 
    foo(v); 
    ^

У меня нет доступа к любому другому компилятору, который поддерживает C++ 14 generic lambdas, поэтому Clan g - это все, что я тестировал.

Это моя ошибка или ошибка Клана?

Я склоняюсь к идее, что это ошибка в правилах создания шаблонов Клана: Кланг, кажется, относится к auto как первоклассный гражданин в мире типов, а не как индикатор для выполнения вычитания типа.

test.cc:34:14: error: invalid argument type 'auto' to unary expression 
     bar((+forward_if<Container>)(elt)); 
      ^~~~~~~~~~~~~~~~~~~~~~ 

снова:

template<class T> T x{0}; // good 
template<class T> auto x = T{0}; // bad 

int main() 
{ 
    return x<int> + x<long>; 
} 

bad.cc:6:19: error: invalid operands to binary expression ('auto' and 'auto') 
+1

фрагмент кода в вашем вопросе компилируется нормально (после изменения '' class' к struct' для доступности) с последней версией лязгом ++. Это говорит о том, что ошибка, которую вы видите, является ошибкой компилятора, которая была исправлена. – dyp

+0

@ dyp Ура! Можете ли вы рассказать мне о выходе «clang -version»? и в идеале я бы хотел найти онлайн-сервис, например ideone или godbolt, который поддерживает эту версию Clang. (http://ideone.com/jRZ5SD даже не поддерживает переменные шаблоны.) – Quuxplusone

+0

[melpon.org/wandbox](http://melpon.org/wandbox) обычно имеет самые последние версии как g ++, так и clang ++, но Я не уверен, что вы можете настроить переключатели компилятора на что-то разумное (например, '-std = C++ 1y') - изменить: ah, вы можете настроить его в левом нижнем углу страницы. [coliru.stacked-crooked.com] (http: // http: //coliru.stacked-crooked.com/) также имеет достаточно последние версии как g ++, так и clang ++. Я использовал clang версии 3.7.0 (ствол 228504), который должен быть наклонным сундуком. – dyp

ответ

0

Per @ DYP и комментарии @ Илдъярн в: Да, это была ошибка в Clang 3.4 (и, возможно, 3,5). Он зафиксирован в Clang 3.7.0 (и, возможно, раньше). Различные версии Clang доступны на Wandbox.

И here is the C++14 code I was trying to construct!

#include <type_traits> 

template <class T> 
struct forward_wrapper { 

    template <class U, class Enable = std::enable_if_t<(sizeof(std::remove_reference<U>), std::is_reference<T>::value)>> 
    static U forward(U&& u) { 
     return u; 
    } 

    template <class U, class Enable = std::enable_if_t<(sizeof(std::remove_reference<U>), !std::is_reference<T>::value)>> 
    static decltype(auto) forward(U&& u) { 
     return static_cast<typename std::remove_reference<U>::type &&>(u); 
    } 
}; 

template <class T> auto forward = 
    [](auto&& u) -> decltype(auto) { return forward_wrapper<T>::forward(u); }; 

// -------- 

#include <stdio.h> 
#include <vector> 

void bar(int &) { puts("Called copy function"); } 
void bar(int &&) { puts("Called move function"); } 

template<class Container> 
void foo(Container&& c) { 
    for (auto&& elt : c) { 
     bar(forward<Container>(elt)); 
    } 
} 

int main() { 
    std::vector<int> v = {1,2}; 
    foo(v); 
    foo(std::move(v)); 
}