2017-02-10 1 views
0

나는 매개 변수 팩을 통해 재귀 템플릿 기능을 가지고있다. 본질적으로 something.Get<A,B,C>()something.Get<A>().Get<B>().Get<C>()으로 매핑하기위한 것입니다. 재귀 템플릿 함수가 Clang으로 컴파일되지 않습니까?

은 (겹 아래 완전 독립형 소스)을 수행하여 달성 할 수 first_true에 해당하는 첫 번째 요소의 인덱스를 반환

template <typename... Pack> class Struct { 
    std::tuple<Pack...> mTuple; 
    template <typename Type> auto &GetRef_internal() { 
    return std::get<first_true<std::is_same<Type, Pack>::value...>::value>(
     mTuple); 
    } 
public: 
    template <typename Current> Current &GetRef() { 
    return GetRef_internal<Current>(); 
    } 
    template <typename Current, typename... Next, 
      typename std::enable_if<sizeof...(Next) != 0>::type * = nullptr> 
    auto &GetRef() { 
    auto current = GetRef_internal<Current>(); 
    return current.GetRef<Next...>(); 
    } 
}; 

.

이 g 용 ++로 컴파일하고 겉으로는 MSVC 너무 online compiler를 사용하여. clang ++로 컴파일 할 때 다음과 같은 오류가 발생합니다.

test.cxx:40:31: error: expected '(' for function-style cast or type construction 
    return current.GetRef<Next...>(); 
          ~~~~^ 
test.cxx:38:9: error: cannot deduce return type 'auto &' for function with no return statements 
    auto &GetRef() { 
     ^
test.cxx:48:12: note: in instantiation of function template specialization 'Struct<Struct<int, Struct<float, float> >, Struct<char>, int>::GetRef<Struct<int, Struct<float, float> >, Struct<float, float> , nullptr>' requested here 
      .GetRef<Struct<int, Struct<float, float>>, Struct<float, float>>(); 
     ^
2 errors generated. 

어떤 일이 발생할 수 있습니까?

p.s. 실제 '생산 코드'는보기가보기보다 유용하지만 여기에 게시하는 것이 너무 많습니다.

============================================== ===========================

#include <tuple> 
#include <type_traits> 

// Template to check if condition holds true for all members of a parameter 
// pack. 
template <bool... b> struct BoolArray {}; 
template <bool... b> 
using all_true = std::is_same<BoolArray<b...>, BoolArray<(b, true)...>>; 

//helper type trait 
template <bool... b> struct first_true { 
    template < 
     unsigned index = 0, 
     typename std::enable_if<index<sizeof...(b)-1>::type * = 
            nullptr> static constexpr unsigned check() { 
    return std::get<index>(std::make_tuple(b...)) ? index : check<index + 1>(); 
    } 
    template <unsigned index = 0, 
      typename std::enable_if<index >= sizeof...(b)-1>::type * = nullptr> 
    static constexpr unsigned check() { 
    return std::get<index>(std::make_tuple(b...)) ? index : 0; 
    } 
    static constexpr unsigned value = first_true<b...>::check(); 
}; 

//The actual problem struct 
template <typename... Pack> class Struct { 
    std::tuple<Pack...> mTuple; 
    template <typename Type> auto &GetRef_internal() { 
    return std::get<first_true<std::is_same<Type, Pack>::value...>::value>(
     mTuple); 
    } 
public: 
    template <typename Current> Current &GetRef() { 
    return GetRef_internal<Current>(); 
    } 
    template <typename Current, typename... Next, 
      typename std::enable_if<sizeof...(Next) != 0>::type * = nullptr> 
    auto &GetRef() { 
    auto current = GetRef_internal<Current>(); 
    return current.GetRef<Next...>(); 
    } 
}; 

int main() { 
    // Define a random nested struct 
    Struct<Struct<int, Struct<float, float>>, Struct<char>, int> myStruct; 
    // Then retrieve one of the substructures to instantiate the template 
    auto substruct = 
     myStruct 
      .GetRef<Struct<int, Struct<float, float>>, Struct<float, float>>(); 
return 0; 
} 

답변

0

current.GetRef<Next...>는 종속 이름입니다, 그래서 당신은 그 GetRef 이름을 템플릿을 지정해야 template 키워드를 사용하여 :

return current.template GetRef<Next...>(); 

종속 이름에 대한 자세한 내용은 Where and why do I have to put the "template" and "typename" keywords?를 참조하십시오.

+0

이 일했다! 오늘 새로운 것을 배웠습니다. 그것이 가능한 한 빨리이 대답을 받아 들일 것입니다. g ++가 -pedantic으로 그것을 해결한다는 것에 흥미 롭습니다. 당신이있는 경우 사양 @CodingCat –

+0

말한다 "foo.bar을 <", "바"가 처음 "foo는"의 클래스에보고해야 템플릿인지 여부를 알 수 있습니다. 그리고 거기에 "막대"가 없다면, 전체 표현의 문맥에서 찾아야합니다. 그러나 객체의 클래스에 있는지 여부를 확인하려면 먼저 주변 템플리트가 인스턴스화 될 때까지 대기해야합니다. Clang이 그렇게합니다. GCC는 템플릿이 아니라고 생각합니다. 이것은 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55576의 문제이기도합니다. 그 버그 보고서에서 GCC는 유효한 프로그램을 거부합니다. –

+0

"템플릿"disambiguator의 전체 목적은 컴파일러가 이름이 템플릿인지 결정하는 데 도움이됩니다. 그러나 GCC는 disambiguator를 사용하지 않고, 스스로이 작업을 수행하기로 결정, 따라서 구성원으로 표현의 맥락에서 "GetRef"를 찾습니다. 나는이 GCC 행동이 정확하다고 생각하지 않는다. –

관련 문제