2017-12-24 3 views
1

나는이 질문에 다음, 아이겐 유형에 대한 템플릿 특수화 몇 가지 함수를 작성하는 것을 시도하고있다 : Eigen: type deduction in template specialization of base-class템플릿 전문 기능

나는이 쓴 :

#include <type_traits> 
#include <Eigen/Core> 

namespace isEigenPlainObjectBaseDetail { 
    template <typename T> 
    std::true_type test(const Eigen::PlainObjectBase<T>); 
    std::false_type test(...); 
} 
template <typename T> 
struct isEigenPlainObjectBase : 
     public decltype(isEigenPlainObjectBaseDetail::test(std::declval<T>())) {}; 

template <typename T, typename Enable = void> 
void foo(T& obj) { 
    std::cout << "Generic Called!\n"; 
} 

template <typename T, typename std::enable_if<isEigenPlainObjectBase<T>::value>::type> 
void foo(T& obj) { 
    std::cout << "Eigen Specialization Called!"; 
} 

int main() { 
    Eigen::MatrixXd m; 
    Eigen::VectorXd v; 
    int i = 0; 
    foo(i); 
    foo(m); 
    foo(v); 
    return 0; 
} 

을하지만 매번 일반적인 함수를 호출 :

Generic Called! 
Generic Called! 
Generic Called! 

내가 뭘 잘못하고 있니? Eigen 행렬 및 벡터가있는 함수의 템플릿 전문화는 어떻게 작성합니까?

답변

0

확실하지 않음이 유일한 문제이다 (더 아이겐가 설치되어 있지, 그래서 내가 확인할 수 없습니다, 죄송합니다) ...

당신이 할 수있는 부분 구체화 구조체와 클래스가 아닌 기능을하지만.

그래서이 코드

template <typename T, typename Enable = void> 
void foo(T& obj) { 
    std::cout << "Generic Called!\n"; 
} 

template <typename T, typename std::enable_if<isEigenPlainObjectBase<T>::value>::type> 
void foo(T& obj) { 
    std::cout << "Eigen Specialization Called!"; 
} 

작동하지 않습니다와 나는 컴파일 놀랐어요.

편집 : Quentin (감사합니다!)이 지적한대로 두 번째 템플리트의 두 번째 매개 변수는 비 유형 매개 변수입니다. 따라서 두 형식 사이에 충돌이 없지만 두 번째 형식은 형식이 아닌 형식의 매개 변수 형식이 void이기 때문에 제외됩니다. 그리고 이것은 허용되지 않습니다.

SFINAE를 사용하려면 class 또는 struct을 통과해야합니다.

template <typename T, typename = void> 
struct foo 
{ 
    static void func (T & obj) 
    { std::cout << "Generic Called!\n"; } 
}; 

template <typename T 
struct foo<T, typename std::enable_if<isEigenPlainObjectBase<T>::value>::type> 
{ 
    static void func (T & obj) 
    { std::cout << "Eigen Specialization Called!"; } 
}; 

foo<decltype(i)>::func(i); 
foo<decltype(m)>::func(m); 
foo<decltype(v)>::func(v); 

로 사용할 수 있습니다 같은 아마 당신은 bar() 템플릿 도우미 함수를 정의 할 수 있습니다

template <typename T> 
void bar (T & t) 
{ foo<T>::func(t); } 

단순히 그것의

bar(i); 
bar(m); 
bar(v); 

아니면 전화 바보 ler는 태그 발송을 사용합니다.

당신은 foo() 몇 전에, 당신이

template <typename T> 
void bar (T & t) 
{ foo(t, isEigenPlainObjectBase<T>{}); } 

같은 bar() 도우미 기능을 올바른 foo()을 선택할 수 있어야 다른 추가 매개 변수

template <typename T> 
void foo (T &, std::false_type const &) 
{ std::cout << "Generic Called!\n" } 

template <typename T> 
void foo (T &, std::true_type const &) 
{ std::cout << "Eigen Specialization Called!"; } 

를 수신하고 정의하는 경우 , 단지 호출

bar(i); 
bar(m); 
bar(v); 

[주의 : 테스트하지 않음]

+1

두 번째 함수는 오버로드이며, 두 번째 템플릿 매개 변수가 비 유형 변수이기 때문에 유효하다고 생각합니다. 그러나'std :: enable_if <> :: type'은'void'이기 때문에 항상 SFINAE가 출력되지 않습니다. 이것은 허용되지 않습니다. – Quentin

+0

@Quentin - 'typename = typename std :: enable_if'가 아니라'typename std :: enable_if' 만 주목했습니다. 대답이 명시 적으로 수정되었습니다. 감사! – max66

+0

알았어, 좋은 정보! : D 나는 gcc로 컴파일했고, msvc로 시도하지 않았다. 그러나 물론 그것은 작동하지 않고 있었다! 템플릿을 사용하여 모든 고유 일반 객체를 구분할 수있게 해주는 Eigen 라이브러리에서 설계된 것을 기대하고있었습니다! –

0

지나가는 두 가지 유형의 함수를 전문화하려는 경우 생각보다 훨씬 간단합니다.

현재 코드 :

template <typename T, typename Enable = void> 
void foo(T& obj) { 
    std::cout << "Generic Called!\n"; 
} 

template <typename T, typename std::enable_if<isEigenPlainObjectBase<T>::value>::type> 
void foo(T& obj) { 
    std::cout << "Eigen Specialization Called!"; 
} 

새로운 코드 :

template <typename T> 
void foo(T& obj); 

template <> 
void foo(Eigen::MatrixXd& obj) { 
    std::cout << "Eigen Specialization Called!" << std::endl; 
} 

template <> 
void foo(Eigen::VectorXd& obj) { 
    std::cout << "Eigen Specialization Called!" << std::endl; 
} 

template <typename T> 
void foo(T& obj) { 
    std::cout << "Generic Called!" << std::endl; 
} 

주, 테스트 컴파일되지 않습니다.

관심있는 유형에 특성을 추가하는 방법이 있습니다. 어떻게 할 수 있습니까?

내가 권하는 방법은 다음과 같습니다. (컴파일/테스트되지 않음)

template<typename T> 
struct isEigenTrait; 

//specializations for all of the eigen types you are interested in 
template<> 
struct isEigenTrait<Eigen::MatrixXd> { 
    typedef std::true_type value; 
}; 

//... 

template<typename T> 
struct isEigenTrait { 
    typedef std::false_type value; 
}; 

template<class T, std::enable_if_t<isEigenTrait<T>::value, true_type> = 0> 
void foo(T& obj) { 
    std::cout << "Eigen Specialization Called!" << std::endl; 
} 

template<class T, std::enable_if_t<isEigenTrait<T>::value, false_type> = 0> 
void foo(T& obj) { 
    std::cout << "Generic Called!" << std::endl; 
} 

코드가 C++ 참조에서 수정되었으므로 작동해야합니다.

단일 특성으로 모든 고유 행렬을 얻으려면 다음과 같이 작동해야한다고 생각합니다.

//specializations for all of the eigen types you are interested in 
template<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime> 
struct isEigenTrait< Eigen::Matrix<Scalar, RowsAtCompileTime, ColsAtCompileTime> > { 
    typedef std::true_type value; 
}; 

isEigenTrait를 추가하려는 각 템플릿 유형에 대해 동일한 작업을 수행해야 할 수 있습니다.

+0

나는 이미 이 솔루션을 사용하지만 많은 중복 코드가 생성되었습니다. 다른 고유 한 행렬 (Row major 또는 Column major, static 또는 dynamic)을 많이 사용합니다.이 경우 단일 전문화를 통해 "catch "이 모든 매트릭스! –

+0

정말로 알고 싶다면 enable_if http://en.cppreference.com/w/cpp/types/enable_if의 설명서를 확인하십시오. – ceorron

+0

위의 수정 된 답변 참조 – ceorron