友元函数不可从模板类运算符重载中调用

Friend function not callable from template class operator overload

提问人:Chimess 提问时间:7/24/2023 最后编辑:Chimess 更新时间:7/24/2023 访问量:35

问:

我正在尝试设置一个用于表示 2-3D 向量的类。它是一个模板类,采用坐标类型(坐标的积分/点表示)和 Dim(维度数)作为其模板定义的一部分。

#pragma once

#include <iostream>
#include <array>
#include <type_traits>

#define DIM2        2
#define DIM3        3

typedef size_t Dimensions;

namespace Geo{

    template<class Coordinate_type, Dimensions dim = DIM3>
    class Vector{

        static_assert(std::is_arithmetic<Coordinate_type>::value, "Vector class can only contain Integral or Floating point types");
        static_assert(dim >= DIM2, "Vector dimension should be at least 2D");

        // friends

            // Functions
         #if 1
        template <class type, Dimensions d>
        friend Vector<type, d> CrossProduct(const Vector<type, d>& first, const Vector<type, d>& second);
        #else
        friend Vector<Coordinate_type, dim> CrossProduct(const Vector<Coordinate_type, dim>& first, const Vector<Coordinate_type, dim>& second);
        #endif
        
        std::array<Coordinate_type, dim> coords;

    public:
        // Constructors
        Vector() {}
        // Array Constructor
        Vector(std::array<Coordinate_type, dim> _coords) : coords(_coords) {}
        // 3D explicit constructor
        Vector(Coordinate_type _x, Coordinate_type _y, Coordinate_type _z) :  coords({_x, _y, _z}) {}
        Vector(Coordinate_type _x, Coordinate_type _y) :  coords({_x, _y}) {}

        inline Vector<Coordinate_type, dim> operator+(const Vector<Coordinate_type, dim>& other);
        inline Coordinate_type operator[](const int idx) const;
        inline bool operator<(const Vector<Coordinate_type, dim>& other) const;

        inline float Magnitude() const;
        inline int GetDimension() const;
        inline Vector<Coordinate_type, dim> Normalize() const;

    };

    template<class Coordinate_type, Dimensions dim>
    inline Coordinate_type Vector<Coordinate_type, dim>::operator[](int idx) const{
        return this->coords[idx];
    }

    template<class Coordinate_type, Dimensions dim>
    inline Vector<Coordinate_type, dim> Vector<Coordinate_type, dim>::operator+(const Vector<Coordinate_type, dim>& other){

    }

    template<class Coordinate_type, Dimensions dim>
    inline int Vector<Coordinate_type, dim>::GetDimension() const{ return this->coords.size(); }



    template<class Coordinate_type, Dimensions dim>
    inline float Vector<Coordinate_type, dim>::Magnitude() const{

        float ret = 0;
        for(int i = 0; i < this->coords.size(); i++){
            ret += (*this)[i] * (*this)[i];
        }

        return std::sqrt(ret);
    }


    template<class Coordinate_type, Dimensions dim>
    inline Vector<Coordinate_type, dim> Vector<Coordinate_type, dim>::Normalize() const{
        // Store magnitude of vector
        Coordinate_type magnitude = this->Magnitude();
        
        // Copy vector
        std::array<Coordinate_type, dim> temp;
        for(int i = 0; i < this->GetDimension(); i++){
            // Store the normalized component
            temp[i] = (*this)[i]/magnitude;
        }

        return Vector<Coordinate_type, dim>(temp);
    }

    template<class Coordinate_type, Dimensions dim>
    inline bool Vector<Coordinate_type, dim>::operator<(const Vector<Coordinate_type, dim>& other) const{

        // Call to CrossProduct function
        auto crossProd = CrossProduct( this->Normalize(), other.Normalize() );

        //  other logic ...
        return true;
    }


    template<class Coordinate_type, Dimensions dim>
    Vector<Coordinate_type, dim> CrossProduct( const Vector<Coordinate_type, dim>& first,  const Vector<Coordinate_type, dim>& second){
        
        // Definition here
        return Vector<Coordinate_type, dim> (first.coords[0], first.coords[1], first.coords[2]);
    }


}


-----------------------------------------

// main.cpp

int main() {

    Geo::Vector<int, 3> v1(1,2,3);
    Geo::Vector<int, 3> v2(2,4,6);

    if(v1 < v2){
        std::cout<< "v1 is less than v2" << std::endl;
    }

return 0;
}

它具有用于比较向量的运算符重载。我只需要根据它们的大小来比较平行向量。

为了检查并行性,我使用叉积。定义为朋友。但是当我尝试从“<”运算符重载中调用它时,我总是收到错误。

错误内容如下:Undefined symbols for architecture arm64: "jmk::CrossProduct(jmk::Vector<int, 3ul> const&, jmk::Vector<int, 3ul> const&)", referenced from: jmk::Vector<int, 3ul>::operator<(jmk::Vector<int, 3ul> const&) const in main.o ld: symbol(s) not found for architecture arm64 clang: error: linker command failed with exit code 1 (use -v to see invocation) make: *** [main] Error 1

CrossProduct 函数可以从 main 调用,没有任何错误,但从运算符重载调用时。它抛出编译错误。

C++ 模板 operator-重载 friend-function inline-functions

评论

1赞 273K 7/24/2023
你仔细阅读过警告吗? 稍后,您将定义一个函数模板。note: (if this is not what you intended, make sure the function template has already been declared and add '<>' after the function name here)warning: friend declaration 'Vector<Coordinate_type, dim> CrossProduct(const Vector<Coordinate_type, dim>&, const Vector<Coordinate_type, dim>&)' declares a non-template function [-Werror=non-template-friend]
0赞 n. m. could be an AI 7/24/2023
不能以这种方式定义 2D 向量的叉积。也不要试图定义向量,它没有一个合理的定义。如果要比较量级,请比较量级。operator<
0赞 Chimess 7/24/2023
@273K 不清楚你的意思。这个 my friend 函数在模板类中是向前声明的。当我在类声明之后定义模板标头时,会添加模板标头。
0赞 Chimess 7/24/2023
@n.m.willseey'allonReddit 是的,我在网上找不到任何简明扼要的内容。但是语法问题的解决方案仍然会有所帮助
0赞 273K 7/24/2023
你声明了一个自由函数,这是由警告告知的。然后你定义一个函数模板,即其他函数,而不是那个自由函数。free 函数未定义。

答:

1赞 user22232969 7/24/2023 #1

您不关心提供最小的、可重复的示例,因此这是一个修复缺失部分的解决方案。

您声明了一个免费的好友函数。然后定义一个函数模板,并保持自由函数未定义。 启用与代码类似的代码,并获取链接器错误“未定义引用”。 启用修复。#if 0CrossProduct()#if 1

#include <iostream>

using Dimensions = int;

template <class Coordinate_type, Dimensions dim = 3>
class Vector {
#if 1
  template <class type, Dimensions d>
  friend Vector<type, d> CrossProduct(const Vector<type, d>& first,
                                      const Vector<type, d>& second);
#else
  friend Vector<Coordinate_type, dim> CrossProduct(
      const Vector<Coordinate_type, dim>& first,
      const Vector<Coordinate_type, dim>& second);
#endif

 public:
  // Constructors
  Vector() {}

  // 3D explicit constructor
  Vector(Coordinate_type _x, Coordinate_type _y, Coordinate_type _z) {}

  inline bool operator<(const Vector<Coordinate_type, dim>& other) const;
};

template <class Coordinate_type, Dimensions dim>
inline bool Vector<Coordinate_type, dim>::operator<(
    const Vector<Coordinate_type, dim>& other) const {
  // Call to CrossProduct function
  auto crossProd = CrossProduct(*this, other);
  //  other logic ...
  return true;
}

template <class Coordinate_type, Coordinate_type dim>
Vector<Coordinate_type, dim> CrossProduct(
    const Vector<Coordinate_type, dim>& first,
    const Vector<Coordinate_type, dim>& second) {
  // Definition here
  return first;
}

// main.cpp

int main() {
  Vector<int, 3> v1(1, 2, 3);
  Vector<int, 3> v2(2, 4, 6);

  if (v2 < v1) {
    std::cout << "v1 is less than v2" << std::endl;
  }

  return 0;
}

生活的例子:https://godbolt.org/z/ExYcjKErM

评论

0赞 Chimess 7/24/2023
这可行,但为什么预处理器条件检查需要包含在友元类的声明中?
0赞 7/24/2023
这不是预处理器条件检查,我这样做是为了在您的代码和我的修复程序之间轻松切换,而不是复制整个代码。#else 旧的部分都可以移除。