当前位置: 首页 > 知识库问答 >
问题:

可以在模板参数中使用decltype吗?

熊烨
2023-03-14

我试图重载一个乘法运算符,但不想输入多个重载函数来考虑整数与浮点、整数与双精度、浮点与整数的乘法等等。。。我希望编写一个重载运算符来解释所有带浮点数、整数和double的乘法组合,并得到正确的返回类型。我得到的错误是,没有找到接受“Widget::Widget”类型的右操作数的运算符(或者没有可接受的转换)。我想这是因为我正在使用decltype来设置返回对象小部件的模板类型。如果返回不是模板对象,则使用尾部返回类型有效。

下面是一个重载运算符的示例

template<typename T1, typename T2>
auto
operator*(const Widget<T1>& aWidge, const Widget<T2>& bWidge) -> Widget<decltype(aWidge.x*bWidge.x)>
{
    Widget<decltype(aWidge.x*bWidge.x)> result;

    //do stuff needed when multiplying two Widgets

    return result;
}

template<typename T>
Widget<T>& Widget<T>::operator=(const Widget<T>& aWidget)
{
    x = aWidget.x;

    return *this;
}

下面是模板类的一个例子

template<typename T> class Widget
{
    private:
        T x;
    public:
        Widget();
        ~Widget();
        void SetX(T value);
        Widget<T>& operator=(const Widget<T>& aWidget);
}

示例Main.cpp

int main()
{
    Widget<int> aWidge;
    Widget<float> bWidge;
    Widget<float> cWidge;

    aWidge.SetX(2);
    bWidge.SetX(2.0);

    cWidge = aWidge*bWidge; //this should give a float return type
}

共有2个答案

巫健柏
2023-03-14

视觉工作室2012

不要介意那些草率的代码。这是一个快速修复的代码,没有正确编译开始(不管自动decltype问题)。

template<typename T>
class Widget
{
public:
    T x;
public:
    Widget()
        : x(666)
    {}

    ~Widget() {}

    void SetX(T value)
    {
        x = value;
    }

    Widget<T>& operator=(const Widget<T>& aWidget)
    {
        x = aWidget.x;

        return *this;
    }
};


template<typename T1, typename T2>
auto operator*(const Widget<T1>& aWidge, const Widget<T2>& bWidge) -> Widget<typename std::remove_const<decltype(aWidge.x*bWidge.x)>::type>
{
    Widget<typename std::remove_const<decltype(aWidge.x*bWidge.x)>::type> result;

    result.x = aWidge.x * bWidge.x;

    return result;
}



int main ()
{
    Widget<int> aWidge;
    Widget<float> bWidge;
    Widget<float> cWidge;

    aWidge.SetX(2);
    bWidge.SetX(2.0);

    cWidge = aWidge*bWidge; //this should give a float return type
}
翟嘉志
2023-03-14

仔细阅读错误消息,问题很明显:

candidate template ignored: substitution failure [with T1 = int, T2 = float]: 'x' is
      a private member of 'Widget<int>'

非成员二进制运算符*试图在其声明(和定义)中访问私有成员x。由于您有一个setter函数,一个简单的解决方案是还定义一个getter,并且只通过该函数访问成员x

template<typename T> class Widget
{
    private:
        T x;

    public:
        Widget() {}
        ~Widget() {}
        void SetX(T value) {}
        T& GetX() { return x; }
        const T& GetX() const { return x; }
        Widget<T>& operator=(const Widget<T>& aWidget);
};

template<typename T1, typename T2>
auto
operator*(const Widget<T1>& aWidge, const Widget<T2>& bWidge)
-> Widget<decltype(aWidge.GetX()*bWidge.GetX())>
{
    Widget<decltype(aWidge.GetX()*bWidge.GetX())> result;
    //...
    return result;
}

另一个选择是让操作员*成为朋友:

template<typename T> class Widget
{
    private:
        T x;

    template<typename T1, typename T2>
    friend auto
    operator*(const Widget<T1>& aWidge, const Widget<T2>& bWidge)
    -> Widget<decltype(aWidge.x*bWidge.x)>;

    public:
        Widget() {}
        ~Widget() {}
        void SetX(T value) {}
        Widget<T>& operator=(const Widget<T>& aWidget);
};

template<typename T1, typename T2>
auto
operator*(const Widget<T1>& aWidge, const Widget<T2>& bWidge)
-> Widget<decltype(aWidge.x*bWidge.x)>
{
    Widget<decltype(aWidge.x*bWidge.x)> result;

    return result;
}

或者,让它成为一个成员函数(感谢WhozCraig)。

你可能还需要

typename std::decay<decltype(aWidge.x*bWidge.x)>::type

而不仅仅是decltype(aWidge.x*bWidge.x)

其他选择包括

typename std::decay<decltype(std::declval<T1>()*std::declval<T2>())>::type

完全绕过了前面的问题(感谢亚当),或者

typename std::common_type<T1, T2>::type

它应该适合这个目的,可以说是最简单的形式。

 类似资料:
  • 我正在学习C 17非类型模板参数的新功能。我编写了一个简单的代码片段,如下所示: 据我所知,福 但是,语句使用clang、MSVC 19.27编译,但在GCC 10.2、MSVC 19.25编译时失败。 我的问题是:为什么编译器的行为不同?标准对此有何规定? 链接到编译器资源管理器: 叮当声https://godbolt.org/z/66M695 海湾合作委员会https://godbolt.or

  • 在里面https://github.com/stlab/libraries/blob/main/stlab/concurrency/main_executor.hpp,我读到 decltype(f)的意义是什么,为什么不直接使用f?

  • (...)“m”不约束类型(...)

  • 问题内容: 我的问题如标题中所述。我正在尝试做类似的事情: 我得到错误: 是否有其他方法可以在模板中进行模量计算? 问题答案: 添加具有所需逻辑的模板功能。例如: 游乐场的例子

  • 问题内容: 我对棱角玉和玉都陌生。我想知道角度是否只能与HTML一起使用,还是可以在玉模板中使用相同的角度调用?我只看到有角度的模板与HTML一起使用,还没有在任何翡翠模板中找到它。有可能这样做吗?玉模板中的棱角看起来如何? 问题答案: 是的你可以。它看起来像:

  • 我有以下问题:一个类模板a,有几个模板参数,我想构建一个类B,它以a为模板参数,并提取a的第一个模板参数,以便在某种方法中使用它(想想从std::vector 中提取int并返回默认的int{})。 我知道这种天真的方法不会编译,但我不知道如何实现这样的东西。感谢任何提示。