这就是我最终做的事情:
template<int M, int N, typename T = double>
class mat {
public:
// constructor
template <typename... Args>
mat(Args... args) : buf({ args... }) {
static_assert(sizeof...(Args) == M*N || sizeof...(Args)==0, "Wrong number of arguments in constructor.");
}
// etc...
}
// the following aliases replace all those typedefs in the question
template<index_t N, typename T=double>
using row = mat<1, N, T>;
template<index_t M, typename T=double>
using col = mat<M, 1, T>;
template <typename T=double, typename... Args>
col<sizeof...(Args), T> c(Args... args) {
return col<sizeof...(Args), T>({ args... });
}
template <typename T=double, typename... Args>
row<sizeof...(Args), T> r(Args... args) {
return row<sizeof...(Args), T>({ args... });
}
这允许像
c(1.0, 2.0, 3.0); // returns a col<3>, which is a mat<3,1>
r(1.0, 2.0); // returns a row<2>, which is a mat<1,2>
r<float>(1.0f, 2.0f); // returns a row<2, float>
如果上面最后一行中的模板函数有一种简单的方法可以从函数的参数类型推断类型参数,我很想知道它。
编辑:(新版本包含@Yakk 的建议。)
typedef short index_t;
template<int M, int N, typename T = double>
class mat {
public:
mat() {
}
template <typename... Args, std::enable_if_t<(sizeof...(Args)==M*N), int> = 0> // static assertion doesn't work for external detection of validity, which is needed I think to avoid signature conflict with default, copy, move constructors etc.
mat(Args&&... args) : buf({ std::forward<Args>(args)... }) {
//static_assert(sizeof...(Args) == M*N || sizeof...(Args) == 0, "Wrong number of arguments in constructor.");
}
public:
T& operator()(index_t i, index_t j) {
return buf[i + j*M];
}
T& operator[](index_t k) {
return buf[k];
}
// etc... various matrix operations
private:
std::array<T, M*N> buf;
};
// etc... various matrix operators
// aliases for row and col
template<index_t N, typename T=double>
using row = mat<1, N, T>;
template<index_t M, typename T=double>
using col = mat<M, 1, T>;
// short-hand "literals"
template <typename... Args>
col<sizeof...(Args), typename std::common_type<Args...>::type> c(Args&&... args) {
return col<sizeof...(Args), typename std::common_type<Args...>::type>({ std::forward<Args>(args)... });
}
template <typename... Args>
row<sizeof...(Args), typename std::common_type<Args...>::type> r(Args&&... args) {
return row<sizeof...(Args), typename std::common_type<Args...>::type>({ std::forward<Args>(args)... });
}