2016-10-27 2 views
2

Я пытаюсь (и не удается) написать тип, который определяет выражения Eigen. Другими словами, я хотел бы иметь возможность обнаруживать такие вещи, как A * A + B и т. Д., Где A и B - Eigen матрицы/векторы. В настоящее время я делаю это:Написание черты типа для обнаружения матричных выражений в Eigen

template<typename T> 
struct is_matrix_expression : std::false_type 
{ 
}; 

template<typename Derived> // specialization 
struct is_matrix_expression<Eigen::MatrixBase<Derived>> : 
     std::true_type 
{ 
}; 

Обратите внимание, что Eigen::MatrixBase<Derived> является (шаблон) основанием для всех возможных выражений Эйгена (например, decltype(A * A + B) и т.д.). Тем не менее, общий шаблон выбирается, так как он лучше подходит для чего-то вроде decltype(A * A + B), а не для специалиста MatrixBase<Derived>.

Как я могу каким-то образом обеспечить выделение специализации? Или, другими словами, включить специализацию для всех возможных детей Eigen::MatrixBase<Derived>? Я немного играл с SFINAE по std::is_base_of, но для этого требуется явный тип, а не шаблон, где тип выражения (в данном случае Derived) неизвестен заранее.

Эквивалентно, как я могу определить, является ли тип X дочерним по отношению к Base<T>, для некоторого типа T?

+0

Капля этого 'typename'. Вы пишете 'typename std :: template vector '? –

+0

Является ли [этот старый ответ] (http://stackoverflow.com/a/12182195/27678) полезным? – AndyG

+0

Я думаю, что ваша проблема в том, что 'decltype (A * A + B)' не является 'MatrixBase ' ... это будет похоже на 'CwiseBinaryOp ' right? – Barry

ответ

5

Это определяет, если что-то наследует от bob_template<T>:

template<class T> 
struct bob_template {}; 

template<class T> 
constexpr std::true_type is_bob_f(bob_template<T> const&) { return {}; } 

namespace details { 
    template<template<class...>class Z, class, class...Ts> 
    struct can_apply:std::false_type{}; 
    template<template<class...>class Z, class...Ts> 
    struct can_apply<Z, std::void_t<Z<Ts...>>, Ts...>:std::true_type{}; 
} 
template<template<class...>class Z, class...Ts> 
using can_apply = details::can_apply<Z, void, Ts...>; 

template<class T> 
using is_bob_r = decltype(is_bob_f(std::declval<T const&>())); 

template<class T> 
using is_bob = can_apply< is_bob_r, T >; 

live example.

C++ 20 имеет is_detected, который аналогичен can_apply выше.

std::void_t является C++ 14, но легко писать в C++ 11.

Чтобы прочитать выше в английском:

is_bob<T> истинно тогда и только тогда, когда вы можете вызвать is_bob_r<T>.

is_bob_r может быть вызван, если действительный звонок is_bob_f(T const&).

is_bob_f имеет перегрузку только для is_bob_f(bob_template<T> const&).

can_apply<Z, T> is (производный от) true_type если Z<T> действителен и (получен из) false_type в противном случае.

Так что is_bob<T> является истинным тогда и только тогда, когда T может быть вычислено в bob_template<U> для некоторых U. В основном это означает, что bob_template<U> является (общедоступным) базовым классом T.

+0

Это очень мило и родовое! – vsoftco

4

Нечто подобное здесь следует сделать:

template<typename Derived> 
struct is_matrix_expression 
: std::is_base_of<Eigen::MatrixBase<std::decay_t<Derived> >, std::decay_t<Derived> > 
{}; 

Он печатает справедливо для следующей части кода:

Eigen::MatrixXd A, B; 
std::cout<< is_matrix_expression <decltype(A*A + B)>::value <<std::endl; //true 
std::cout<< is_matrix_expression <int>::value <<std::endl;     //false 

Идея заключается в том, что здесь вы знаете, что базовый класс выглядит следующим образом: а именно, для SomeMatrixXpr, это будет MatrixBase<SomeMatrixXpr> согласно Eigen class hierarchy.Это контрастирует с подходом @ Yakk, который работает для любого типа базовых классов (даже тех, которые не связаны с CRTP).

+0

Это тоже! – vsoftco

+0

@vsoftco: спасибо, я сделал редактирование [почему] (https://eigen.tuxfamily.org/dox/TopicClassHierarchy.html) – davidhigh

+0

Вам не хватает 'typename', я думаю? Но на самом деле вам нужно просто сбрить ':: type' с конца' is_base_of'; наследование достаточно хорошее. – Yakk

Смежные вопросы