仅在部分专业化中提供方法

Providing a method only in a partial specialization

我有 class Matrix,如果 R = 3C = 1,我想要 len() 的专门方法。 我想要标准库的解决方案。 继承不是解决方案,因为它也不会在基础 class 上工作。

这样的普通模板专业化
template<class T>
class Matrix<T, 3, 1> {
public:
    T len() const {return 3;}
};

也会迫使我实施所有其他 Matrix<T, R, C> 方法和东西。 (?)

想法:

#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;
}