2016-08-21 2 views
0

Я хочу определить преобразование в float для матрицы < 1, 1>. Мне трудно понять, как это определить. Если бы я сделать его глобальную функциюОпределение оператора преобразования только для специализированного класса шаблона

template<typename T> 
inline operator T(const matrix<T, 1, 1> &m){ return m(0, 0); } 

я получаю «оператор .. должно быть не статическая функция-члена»

Я могу, конечно, определить его в качестве элемента для общего шаблона матрицы, но тогда это будет определенная для всех матриц - это не то, что я хочу. Я хочу, чтобы он определялся только для конкретного случая матрицы 1x1.

+3

Фактически, функция преобразования 'operaror T()' должна быть функцией члена класса. Он унарный и не может принимать параметр. Однако вы можете использовать специализацию для шаблона 'matrix'. –

ответ

4

Вы должны специализироваться класс для этого, например:

template <typename Base, typename T, std::size_t W, std::size_t H> 
struct MatrixConversion 
{ /*Empty*/ }; 

template <typename Base, typename T> struct MatrixConversion<T, 1u, 1u> 
{ 
    operator const T&() const { return static_cast<const Base&>(*this).m[0][0]; } 
}; 


template <typename T, std::size_t W, std::size_t H> 
struct Matrix : MatrixConversion<Matrix<T, W, H>, T, W, H> 
{ 
    // Your code 
}; 
+0

хорошо использование состава. это всегда так. +1 –

+0

@ RichardHodges: это не * состав *, но * наследование * здесь. – Jarod42

+0

композиция по наследству тогда :) –

1

состав плюс специализация будет наиболее ремонтопригодны подход.

Вы не указали количество измерений в вашем шаблоне шаблона матрицы, поэтому я предположил, что он может быть переменным.

#include <cstdint> 
#include <utility> 

// 
// forward-declare class template for convenience. 
// 
template<class T, std::size_t...Dimensions> 
struct matrix; 

// 
// classes to figure out the storage requirements of a multi-dimensional 
// matrix 
// 
template<class T, std::size_t...Dimensions> struct storage; 
template<class T, std::size_t N> 
    struct storage<T, N> 
    { 
    using type = T[N]; 
    }; 

template<class T, std::size_t...Rest, std::size_t N> 
    struct storage<T, N, Rest...> 
    { 
    using less_dimension_type = typename storage<T, Rest...>::type; 
    using type = less_dimension_type[N]; 
    }; 


// 
// functions for dereferencing multi-dimensional arrays 
// 
template<class Array, class Arg> 
decltype(auto) deref(Array& array, Arg&& arg) 
{ 
    return array[arg]; 
} 

template<class Array, class Arg, class Arg2> 
decltype(auto) deref(Array& array, Arg&& arg, Arg2&& arg2) 
{ 
    return array[arg][arg2]; 
} 

template<class Array, class Arg, class...Args> 
decltype(auto) deref(Array& array, Arg&& arg, Args&&...args) 
{ 
    return deref(deref(array, arg), std::forward<Args>(args)...); 
} 

// 
// prototype for operations we want to conditionally apply 
// 
template<class Matrix> 
struct matrix_conditional_ops 
{ 
    // in the general case, none 
}; 

// 
// compose the matrix class from conditional_ops<> 
//  
template<class T, std::size_t...Dimensions> 
struct matrix 
    : matrix_conditional_ops<matrix<T, Dimensions...>> 
{ 

    template<class...Dims> 
    decltype(auto) at(Dims&&...ds) 
    { 
     return deref(_data, std::forward<Dims>(ds)...); 
    } 

    template<class...Dims> 
    decltype(auto) at(Dims&&...ds) const 
    { 
     return deref(_data, std::forward<Dims>(ds)...); 
    } 

    typename storage<T, Dimensions...>::type _data; 
}; 

// 
// define the condition operations for the <T, 1, 1> case 
//  
template<class T> 
    struct matrix_conditional_ops<matrix<T, 1, 1>> 
    { 
    using matrix_type = matrix<T, 1, 1>; 

    operator T const() { return static_cast<matrix_type const&>(*this).at(0,0); } 
    }; 


int main() 
{ 
    matrix<double, 1, 1> m11; 

    m11.at(0,0) = 6.0; 
    double d = m11; 

    matrix<double, 2, 2> m22; 
    // compile error: 
// double d2 = m22; 

    // bonus points: 

    matrix<double, 3, 5, 2, 7> mxx; 
    mxx.at(2, 4, 1, 6) = 4.3; // probably needs some compile-time checking... 

} 

кто-то может понадобиться, чтобы проверить мою логику для упаковки массива/разыменования ...

+0

Это приносит воспоминания о чтении «Современного дизайна C++» Александреску, только с надлежащим языковым механизмом для обработки списков стилей :) ** (+ 1) ** – StoryTeller

0

Jarod и Richard уже дал вам самые лучшие ответы на мой взгляд, они очень хорошо масштабируется на любое количество операторов со всеми виды ограничений.

Однако, если вы не можете позволить себе переделать свой класс, или все, что вам нужно, это быстро и грязно opertor T() вы можете уйти со следующим

template<typename T, std::size_t N1, std::size_t N2> 
struct Matrix 
{ 
    T m[N1][N1]; 

    operator T() 
    { 
     static_assert(N1 == 1 && N2 == 1, "Only applicable to scalars"); 
     return m[0][0]; 
    } 
}; 

Который является live here.

+0

И тестирование локально, и связанный с ним пример приводят к ошибке компилятора. Можете ли вы отредактировать этот ответ, чтобы он действительно собирался? – Martin

+0

@ Мартин, какая ошибка точно? Обратите внимание, что отказ, когда матрица больше, чем '1x1', является преднамеренным. – StoryTeller

+0

@Martin, удаляя нарушающую линию (попытка вызвать оператора преобразования) делает его [играть красиво] (http://ideone.com/FNLeTU) – StoryTeller

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