仅在部分专业化中提供方法
Providing a method only in a partial specialization
我有 class Matrix
,如果 R = 3
和 C = 1
,我想要 len()
的专门方法。
我想要标准库的解决方案。
继承不是解决方案,因为它也不会在基础 class 上工作。
像
这样的普通模板专业化
template<class T>
class Matrix<T, 3, 1> {
public:
T len() const {return 3;}
};
也会迫使我实施所有其他 Matrix<T, R, C>
方法和东西。 (?)
想法:
- std::enable_if
- constexpr
- ...
#include <vector>
template<class T, std::size_t R, std::size_t C>
class Matrix {
private:
std::vector <T> data;
public:
T len() const;
};
一个肮脏的解决方案是:
template<class T, std::size_t R, std::size_t C>
T Matrix<T, R, C>::len() const {
if constexpr (R == 3 && C == 1) {
return 3;
}
throw std::runtime_error("len not available");
}
一种可能的方法:
注释内嵌注释:
#include <iostream>
template<class T, int R, int C>
struct Matrix;
namespace MatrixOperations
{
// default handling is to prevent compilation
template<class Mat>
auto len(Mat const&) -> void = delete;
// special case for a 3,1 matrix
template<class T>
auto len(Matrix<T, 3, 1> const&) -> T
{
return T(3);
}
};
template<class T, int R, int C>
struct Matrix
{
// ForceDeduce is a defaulted type.
// The argument of this type is defaulted
// It's purpose is to ensure that this function is not actually compiled until it is used
// This will prevent the call to MatrixOperations::len producing an error unless this function
// is called
template<class ForceDeduce = int*>
T len(ForceDeduce = nullptr) const
{
return MatrixOperations::len(*this);
}
};
int main()
{
Matrix <int, 3, 1> m31;
std::cout << m31.len() << std::endl;
Matrix <int, 3, 2> m32;
// fails to compile
// std::cout << m32.len() << std::endl;
}
使用 std::enable_if 的简单解决方案。
#include <type_traits> // std::enable_if
#include <vector> // std::vector
template <class T, std::size_t R, std::size_t C>
class Matrix {
private:
std::vector<T> data;
public:
template <std::size_t C_ = C, typename = std::enable_if_t<C_ == 1>>
std::size_t len() const {
double res = 0;
for (const auto& x : data) {
res += std::pow(x, 2);
}
return std::sqrt(res);
}
};
替代的外联定义:
template <class T, std::size_t R, std::size_t C>
class Matrix {
private:
std::vector<T> data;
public:
template <std::size_t R_ = R,
std::size_t C_ = C,
typename E1 = std::enable_if_t<R_ == 3>,
typename E2 = std::enable_if_t<C_ == 1>>
double len() const;
};
template <class T, std::size_t R, std::size_t C>
template <std::size_t R_, std::size_t C_, typename E1, typename E2>
double Matrix<T, R, C>::len() const {
double res = 0;
for (const auto& x : data) {
res += std::pow(x, 2);
}
return std::sqrt(res);
}
示例:
#include <iostream> // std::cout, std::endl
int main(int argc, char* argv[]) {
Matrix<double, 3, 1> vec;
std::cout << "vec length: " << vec.len() << std::endl;
// output: vec length: 3
// Matrix<double, 3, 3> mat;
// std::cout << "mat length: " << mat.len() << std::endl; // does not compile
return 0;
}
我有 class Matrix
,如果 R = 3
和 C = 1
,我想要 len()
的专门方法。
我想要标准库的解决方案。
继承不是解决方案,因为它也不会在基础 class 上工作。
像
这样的普通模板专业化template<class T>
class Matrix<T, 3, 1> {
public:
T len() const {return 3;}
};
也会迫使我实施所有其他 Matrix<T, R, C>
方法和东西。 (?)
想法:
- std::enable_if
- constexpr
- ...
#include <vector>
template<class T, std::size_t R, std::size_t C>
class Matrix {
private:
std::vector <T> data;
public:
T len() const;
};
一个肮脏的解决方案是:
template<class T, std::size_t R, std::size_t C>
T Matrix<T, R, C>::len() const {
if constexpr (R == 3 && C == 1) {
return 3;
}
throw std::runtime_error("len not available");
}
一种可能的方法:
注释内嵌注释:
#include <iostream>
template<class T, int R, int C>
struct Matrix;
namespace MatrixOperations
{
// default handling is to prevent compilation
template<class Mat>
auto len(Mat const&) -> void = delete;
// special case for a 3,1 matrix
template<class T>
auto len(Matrix<T, 3, 1> const&) -> T
{
return T(3);
}
};
template<class T, int R, int C>
struct Matrix
{
// ForceDeduce is a defaulted type.
// The argument of this type is defaulted
// It's purpose is to ensure that this function is not actually compiled until it is used
// This will prevent the call to MatrixOperations::len producing an error unless this function
// is called
template<class ForceDeduce = int*>
T len(ForceDeduce = nullptr) const
{
return MatrixOperations::len(*this);
}
};
int main()
{
Matrix <int, 3, 1> m31;
std::cout << m31.len() << std::endl;
Matrix <int, 3, 2> m32;
// fails to compile
// std::cout << m32.len() << std::endl;
}
使用 std::enable_if 的简单解决方案。
#include <type_traits> // std::enable_if
#include <vector> // std::vector
template <class T, std::size_t R, std::size_t C>
class Matrix {
private:
std::vector<T> data;
public:
template <std::size_t C_ = C, typename = std::enable_if_t<C_ == 1>>
std::size_t len() const {
double res = 0;
for (const auto& x : data) {
res += std::pow(x, 2);
}
return std::sqrt(res);
}
};
替代的外联定义:
template <class T, std::size_t R, std::size_t C>
class Matrix {
private:
std::vector<T> data;
public:
template <std::size_t R_ = R,
std::size_t C_ = C,
typename E1 = std::enable_if_t<R_ == 3>,
typename E2 = std::enable_if_t<C_ == 1>>
double len() const;
};
template <class T, std::size_t R, std::size_t C>
template <std::size_t R_, std::size_t C_, typename E1, typename E2>
double Matrix<T, R, C>::len() const {
double res = 0;
for (const auto& x : data) {
res += std::pow(x, 2);
}
return std::sqrt(res);
}
示例:
#include <iostream> // std::cout, std::endl
int main(int argc, char* argv[]) {
Matrix<double, 3, 1> vec;
std::cout << "vec length: " << vec.len() << std::endl;
// output: vec length: 3
// Matrix<double, 3, 3> mat;
// std::cout << "mat length: " << mat.len() << std::endl; // does not compile
return 0;
}