2016-10-14 6 views
2

내가 최근에 클래스가 construct라는 특정 템플릿 정적 기능을 포함하는 경우 감지합니다 sfinae 유형의 특성을 만들려고 앞으로 :: 작동하지 않습니다.Sfinae 유형의 특성은 표준이

나는이 구현과 함께 :

template<typename T, typename... Args> 
struct has_template_construct_helper { 
private: 
    template<typename U, typename... As> 
    static std::true_type test(decltype(&U::template construct<As...>)*); 

    template<typename...> 
    static std::false_type test(...); 

public: 
    using type = decltype(test<T, Args...>(nullptr)); 
}; 

template<typename T, typename... Args> 
using has_template_construct = typename has_template_construct_helper<T, Args...>::type; 

는 그 괜찮을 것 문질러서하고 있었다. 나는 gcc로 내 형질을 시험해보고 다음과 같이 clang을 시도했다.

struct TestStruct { 
    template<typename... Args> 
    static auto construct(int a, double b, Args... args) -> decltype(std::make_tuple(a, b, args...)) { 
     return std::make_tuple(1, 2.3, std::forward<Args>(args)...); 
    } 
}; 

// didn't fire! Hurrah! 
static_assert(has_template_construct<TestStruct, std::string>::value, "Don't pass the test"); 

그것은 두 컴파일러 모두에서 작동했다. Clang

내 질문은, GCC : 여기

struct TestStruct { 
    template<typename... Args> 
    static auto construct(int a, double b, Args&&... args) -> decltype(std::make_tuple(a, b, std::forward<Args>(args)...)) 
    { 
     return std::make_tuple(1, 2.3, std::forward<Args>(args)...); 
    } 
}; 

// fires on clang :(
static_assert(has_template_construct<TestStruct, std::string>::value, "Don't pass the test"); 

coliru에 코드 :

그러나, 최대한 빨리 전달 참조를 추가 할 때, 그 소리는 불평을 시작 GCC와 연타 사이에 어떤 일이 잘못된, 그리고 어떻게 내 컴파일러에서 작동하도록 내 코드를 수정할 수 있습니까?


좋아, 지금은 더 혼란 스러워요, 일을 시도했다. std::declval을 사용할 때, 그것은 clang에서 돌아왔다!

struct TestStruct { 
    template<typename... Args> 
    static auto construct(int a, double b, Args&&... args) -> decltype(std::make_tuple(a, b, std::declval<Args>()...)) 
    { 
     return std::make_tuple(1, 2.3, std::forward<Args>(args)...); 
    } 
}; 

// uh?? Works in clang? 
static_assert(has_template_construct<TestStruct, std::string>::value, "Don't pass the test"); 
+0

의 주석을'시험 (...)'와 실제 오류가 대체하는 동안 무엇을 참조하십시오. 도움이 될 것입니다. "표준 : 앞으로 작동하지 않습니다"무엇 – skypjack

+0

도 의미? 컴파일 타임에 알려진 결과와 함께 std :: forward를 호출 할 수없는 유형은 없습니다. – xaxxon

+0

나는 clang의 버그라고 생각합니다. 전달 참조를 추가하면 생성 메소드에 과부하가 걸리므로 오류가 발생합니다. – Arunmu

답변

1

나는 코드가 (++ 또는 g 전달) ++ 그 소리에 실패한 이유를 정확히 모르겠습니다. 그러나 여기에 더 쉬운 대안이 있습니다. 반환형 공제의 decltype에 std::forward<T>를 지정할 때

#include <type_traits> 
#include <tuple> 
#include <string> 

template <typename... T> 
using void_t = void; 

class Stat { 
public: 
    template <typename... T> 
    static auto construct(int a, double b, T&&... t) -> 
     decltype(std::make_tuple(1, 2.3, t...)) 
    { 
     return std::make_tuple(1, 2.3, std::forward<T>(t)...); 
    } 
}; 

template <typename Class, typename... Args> 
constexpr auto does_have_construct(int) 
    -> decltype(&Class::template construct<Args...>, true) 
{ 
    return true; 
} 

template <typename Class, typename... Args> 
constexpr bool does_have_construct(long) { return false; } 

class Stat2 {}; 

int main() { 
    static_assert(does_have_construct<Stat, std::string>(0), "Nope!"); 

    return 0; 
} 

는 연타 특히 불행. 우리가 그것을 제거한다면 아무런 문제가 없습니다. 하지만, 나는 코드의 정확성에 대해 지금은 확실하지 않다!

는 C++ 14에서는 다시 쓸 수있는 class Stat 같이

class Stat { 
public: 
    template <typename... T> 
    static auto construct(int a, double b, T&&... t) 
    { 
     return std::make_tuple(1, 2.3, std::forward<T>(t)...); 
    } 
}; 

당신이 볼 수 있듯이, 우리는이 경우 컴파일러 바보하기 위해 추가 조치를 취할 필요가 없습니다.

+1

흠 ... 당신이 확실 반환 형식에 앞으로 몸이 아닌 사용이 작동하도록되어? 대부분의 경우 예입니다.하지만 다른 기능으로 해결되면 숨겨진 버그 나 컴파일 오류가 발생할 수 있습니까? –

+1

@GuillaumeRacicot : 그래, 그 확실하지 않다가, "나는 코드의 정확성에 대해 지금은 확실하지 않다,하지만!"내가 쓴 이유를 먹으 렴 :). 그러나 C++ 14 방식은 아무 문제가 없습니다. 나는 누군가가 Clang과 함께이 문제에 대해 확대 할 수 있기를 정말로 바란다. 나는 그것에 관해 많이 알 수 없었다. – Arunmu