模板扣除投诉模棱两可的候选人

时间:2018-11-13 05:58:33

标签: c++ templates metaprogramming ambiguous

我打算实现我的“稀疏向量”和“向量”类的乘法运算符。以下简化的代码演示显示了我的问题

Vector.hpp

中的 Vector
#pragma once

template <typename T>
class Vector 
{
public:
    Vector() {}

    template <typename Scalar>
    friend Vector operator*(const Scalar &a, const Vector &rhs)     // #1
    {
        return Vector();
    }
};

SpVec.hpp

中的 Sparse Vector
#pragma once
#include "Vector.hpp"

template <typename T>
class SpVec 
{
public:
    SpVec() {}

    template <typename U>
    inline friend double operator*(const SpVec &spv, const Vector<U> &v)   // #2
    {
        return 0.0;
    }
};

main.cpp 中的测试代码:

#include "Vector.hpp"
#include "SpVec.hpp"


#include <iostream>

int main() 
{
    Vector<double> v;

    SpVec<double> spv;

    std::cout << spv * v;
    return 0;
}

我使用以下代码构建测试程序

g++ main.cpp -o test

给出模棱两可的模板推导错误

main.cpp: In function ‘int main()’:
main.cpp:13:26: error: ambiguous overload for ‘operator*’ (operand types are ‘SpVec<double>’ and ‘Vector<double>’)
        std::cout << spv * v;
                    ~~~~^~~
In file included from main.cpp:2:0:
SpVec.hpp:12:26: note: candidate: double operator*(const SpVec<T>&, const Vector<U>&) [with U = double; T = double]
    inline friend double operator*(const SpVec &spv, const Vector<U> &v)   // #2
                        ^~~~~~~~
In file included from main.cpp:1:0:
Vector.hpp:10:19: note: candidate: Vector<T> operator*(const Scalar&, const Vector<T>&) [with Scalar = SpVec<double>; T = double]
    friend Vector operator*(const Scalar &a, const Vector &rhs)     // #1

我希望#2方法定义更接近于我的调用。

请帮助我了解模棱两可的错误是如何产生的以及如何解决该问题。

2 个答案:

答案 0 :(得分:3)

我想到了另一种想法,即先前类型信息Scalar可以与c++11标准库结构SFAINE feature启用的std::enable_if一起使用。

代码:

Vector.hpp

#pragma once

#include <iostream>
#include <type_traits>

template <typename T>
class Vector
{
public:
    Vector() {}

    template <typename Scalar>
    typename std::enable_if<std::is_arithmetic<Scalar>::value, Vector<T>>::type
    operator*(const Scalar &rhs) const// #1
    {
        std::cout << "Vector * Scalar called." << std::endl;
        return Vector();
    }

    template <typename Scalar>
    inline friend typename std::enable_if<std::is_arithmetic<Scalar>::value, Vector<T>>::type
    operator*(const Scalar &lhs, const Vector &rhs)
    {
        std::cout << "Scalar * Vector called." << std::endl;
        return Vector();
    }
};

SpVec.hpp

#pragma once
#include "Vector.hpp"

#include <iostream>

template <typename T>
class SpVec
{
public:
    SpVec() {}

    template <typename U>
    inline double operator*(const Vector<U> &rhs) const // #2 as member function
    {
        std::cout << "SpVec * Vector called" << std::endl;
        return 0.0;
    }

    template <typename U>
    inline friend double operator*(const Vector<U> &lhs, const SpVec &rhs)
    {
        std::cout << "Vector * SpVec called" << std::endl;
        return 0.0;
    }
};

main.cpp

#include "SpVec.hpp"
#include "Vector.hpp"

#include <iostream>

int main()
{
    Vector<double> v;
    SpVec<double> spv;

    double a = spv * v;
    a = v * spv;

    Vector<double> vt;
    vt = v * 2.0;
    vt = 2.0 * v;

    return 0;
}

使用c++11

构建程序
g++ -std=c++11 main.cpp -o test

结果:

SpVec * Vector called.
Vector * SpVec called.
Vector * Scalar called.
Scalar * Vector called.

答案 1 :(得分:0)

operator*的参数为SpVec<double>Vector<double>。可以解决

operator*(const Scalar &a, const Vector &rhs),其中scalarSpVec<double>rhsVector<double>

它也可以解决

operator*(const SpVec &spv, const Vector<U> &v),其中spv为SpVec<double>,而Udouble

解决此问题的一种方法是将Vector::operator*设为非朋友功能。

Vector operator*(const Scalar &a)     // #1
{
    //The other argument here will be accessed using this pointer.
    return Vector();
}

,您可以将其称为

int main() 
{
   Vector<double> v;
   SpVec<double> spv;
   std::cout << spv * v; // will call #2
   v * spv;              //will call #1
   return 0;
}