【问题标题】:How to check type being assigned to result of call operator?如何检查分配给呼叫操作员结果的类型?
【发布时间】:2020-10-23 04:25:08
【问题描述】:

我正在尝试制作一个简单的矩阵类

“mymat.h”的相关部分

#ifndef _MYMAT_H_GUARD_
#define _MYMAT_H_GUARD_

#include <iostream>

constexpr auto MYMAT_ERR_UNEXPECTED_TYPE = "Error, unexpected type!";
constexpr auto MYMAT_ERR_CODE_UNEXPECTED_TYPE = 0;
constexpr auto MYMAT_ERR_OUT_OF_BOUND = "Error, out of bound!";
constexpr auto MYMAT_ERR_CODE_OUT_OF_BOUND = 0;

template <typename T>
class MYMAT{
public:
    T* data;
    int x, y;
public:
    MYMAT(int x, int y);
    ~MYMAT();

    template <typename C>
    void set(int x, int y, C val);

    template<typename C>
    bool checkType(C val) const;
    
    void print_mat();

public:
    T& operator ()(int x, int y);

private:
    bool inRange(int x, int y);
};
#endif // !_MYMAT_H_GUARD_

template<typename T>
inline MYMAT<T>::MYMAT(int x, int y){
    this->data = new T[x * y]();
    this->x = x;
    this->y = y;
}

template<typename T>
inline MYMAT<T>::~MYMAT(){
    delete this->data;
}

template<typename T>
inline void MYMAT<T>::print_mat(){
    int x, y;
    for (y = 0; y < this->y; y++)
    {
        for (x = 0; x < this->x; x++)
        {
            std::cout << this->data[y * this->x + x] << ' ';
        }
        std::cout << std::endl;
    }
    std::cout << std::endl;
}


template<typename T>
inline bool MYMAT<T>::inRange(int x, int y){
    return !((x < 1) && (x > this->x) && (y < 1) && (y > this->y));
}


template<typename T>
template<typename C>
inline void MYMAT<T>::set(int x, int y, C val){
    if (this->checkType(val)) {
        if (this->inRange(x, y)) {
            this->data[(y - 1) * this->x + (x - 1)] = val;
        }
        else {
            std::cout << MYMAT_ERR_OUT_OF_BOUND;
            exit(MYMAT_ERR_CODE_OUT_OF_BOUND);
        }
    }
    else {
        std::cout << MYMAT_ERR_UNEXPECTED_TYPE;
        exit(MYMAT_ERR_CODE_UNEXPECTED_TYPE);
    }
}


template<typename T>
inline T& MYMAT<T>::operator()(int x, int y)
{
    return this->data[this->x * (y - 1) + (x - 1)];
}

template<typename T>
template<typename C>
inline bool MYMAT<T>::checkType(C val) const
{
    return std::is_same_v<T, C>;
}

下面是我如何调用矩阵并使用set方法

#include <iostream>
#include "mymat.h"

int main()
{

    MYMAT<int> m(3, 3);
    m.set(2, 2, 500);
    m.print_mat();
    m.set(2, 2, 500.0);
    m.print_mat();
}

打印出来

0 0 0 0 500 0 0 0 0 错误,意外类型!

但是当使用呼叫运算符时:

#include <iostream>
#include "mymat.h"

int main()
{

    MYMAT<int> m(3, 3);
    m(2, 2) = 500;
    m.print_mat();
    m(2, 2) = 500.0;
    m.print_mat();
}

打印出来:

0 0 0 0 500 0 0 0 0 0 0 0 0 500 0 0 0 0

如您所见,值从 double 转换为 int。

如何将set() 中的条件应用于呼叫接线员?

【问题讨论】:

  • 无关:_MYMAT_H_GUARD_ 是非法标识符。见What are the rules about using an underscore in a C++ identifier?。它很少咬人,但当它咬人时,它是一个严肃的头脑-。
  • 也无关:为简洁起见,您可能忽略了特殊成员函数,但如果没有,请阅读 The rule of three/five/zero
  • 一旦你返回了T&amp;,你可以做很多事情来防止调用代码弄乱它。如果您想强制对值的更改通过set 中的检查,您可以将operator() 更改为const T&amp; operator(int, int) const,但这会使其成为只读。
  • @NathanPierson 已经搞定了。 m(2, 2) = 500.0; 不进行类型检查,并且兴高采烈地隐式转换为 double 以适应 int。我知道你无法阻止它。

标签: c++ templates operator-overloading


【解决方案1】:

实现你想要的:

m(2, 2) = 500.0; // do custom checks for conversions from
                 // right hand side to left hand side

operator() 返回T&amp; 是行不通的,因为您无法控制到T 的隐式转换。在这种情况下,您无法阻止从doubleint 的转换。

相反,您可以从operator() 返回您自己编写的类型,这样您就可以控制隐式转换。这种类型需要保留左侧的信息,即mthis 指针,以及operator() 的参数。它只需要支持operator= 就可以从右侧检查隐式转换:

private:
struct Wrapper 
{
    MYMAT *t;  // holds onto the this pointer
    int x, y;
    
    template <typename C>
    void operator=(C val) 
    {
        t->set(x, y, val);  // uses MYMAT::set to do the conversion checking
    }
};

现在您可以像这样声明您的operator()

public:
    Wrapper operator ()(int x, int y);

并像这样定义它:

template<typename T>
inline auto MYMAT<T>::operator()(int x, int y) -> Wrapper
{
    return {this, x, y};
}

这是demo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-29
    • 2021-02-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多