gpt4 book ai didi

c++ - 模板化 << friend 在与其他模板化 union 类型相互关联时不工作

转载 作者:行者123 更新时间:2023-11-30 03:10:07 28 4
gpt4 key购买 nike

在处理我的 basic vector library 时,我一直在尝试使用一个很好的语法来进行基于 swizzle 的打印。尝试打印与所讨论 vector 不同维度的调配时会出现问题。在 GCC 4.0 中,我最初为每个 vector 中的每个维度都有 friend << 重载函数(有主体,即使它重复代码),这导致代码工作,即使从未实际调用非 native 维度代码.这在 GCC 4.2 中失败了。我最近意识到(愚蠢的我)只需要函数声明,而不是代码主体,所以我这样做了。现在我在 GCC 4.0 和 4.2 上都收到相同的警告:

LINE 50 warning: friend declaration 'std::ostream& operator<<(std::ostream&, const VECTOR3<TYPE>&)' declares a non-template function

加上其他函数声明的五个相同的警告。

下面的示例代码准确地展示了正在发生的事情,并包含重现问题所需的所有代码。

#include <iostream> // cout, endl
#include <sstream> // ostream, ostringstream, string

using std::cout;
using std::endl;
using std::string;
using std::ostream;

// Predefines
template <typename TYPE> union VECTOR2;
template <typename TYPE> union VECTOR3;
template <typename TYPE> union VECTOR4;

typedef VECTOR2<float> vec2;
typedef VECTOR3<float> vec3;
typedef VECTOR4<float> vec4;

template <typename TYPE>
union VECTOR2
{
private:
struct { TYPE x, y; } v;

struct s1 { protected: TYPE x, y; };
struct s2 { protected: TYPE x, y; };
struct s3 { protected: TYPE x, y; };
struct s4 { protected: TYPE x, y; };

struct X : s1 { operator TYPE() const { return s1::x; } };
struct XX : s2 { operator VECTOR2<TYPE>() const { return VECTOR2<TYPE>(s2::x, s2::x); } };
struct XXX : s3 { operator VECTOR3<TYPE>() const { return VECTOR3<TYPE>(s3::x, s3::x, s3::x); } };
struct XXXX : s4 { operator VECTOR4<TYPE>() const { return VECTOR4<TYPE>(s4::x, s4::x, s4::x, s4::x); } };
public:
VECTOR2() {}
VECTOR2(const TYPE& x, const TYPE& y) { v.x = x; v.y = y; }

X x;
XX xx;
XXX xxx;
XXXX xxxx;

// Overload for cout
friend ostream& operator<<(ostream& os, const VECTOR2<TYPE>& toString)
{
os << "(" << toString.v.x << ", " << toString.v.y << ")";
return os;
}
friend ostream& operator<<(ostream& os, const VECTOR3<TYPE>& toString);
friend ostream& operator<<(ostream& os, const VECTOR4<TYPE>& toString);
};

template <typename TYPE>
union VECTOR3
{
private:
struct { TYPE x, y, z; } v;

struct s1 { protected: TYPE x, y, z; };
struct s2 { protected: TYPE x, y, z; };
struct s3 { protected: TYPE x, y, z; };
struct s4 { protected: TYPE x, y, z; };

struct X : s1 { operator TYPE() const { return s1::x; } };
struct XX : s2 { operator VECTOR2<TYPE>() const { return VECTOR2<TYPE>(s2::x, s2::x); } };
struct XXX : s3 { operator VECTOR3<TYPE>() const { return VECTOR3<TYPE>(s3::x, s3::x, s3::x); } };
struct XXXX : s4 { operator VECTOR4<TYPE>() const { return VECTOR4<TYPE>(s4::x, s4::x, s4::x, s4::x); } };
public:
VECTOR3() {}
VECTOR3(const TYPE& x, const TYPE& y, const TYPE& z) { v.x = x; v.y = y; v.z = z; }

X x;
XX xx;
XXX xxx;
XXXX xxxx;

// Overload for cout
friend ostream& operator<<(ostream& os, const VECTOR3<TYPE>& toString)
{
os << "(" << toString.v.x << ", " << toString.v.y << ", " << toString.v.z << ")";
return os;
}
friend ostream& operator<<(ostream& os, const VECTOR2<TYPE>& toString);
friend ostream& operator<<(ostream& os, const VECTOR4<TYPE>& toString);
};

template <typename TYPE>
union VECTOR4
{
private:
struct { TYPE x, y, z, w; } v;

struct s1 { protected: TYPE x, y, z, w; };
struct s2 { protected: TYPE x, y, z, w; };
struct s3 { protected: TYPE x, y, z, w; };
struct s4 { protected: TYPE x, y, z, w; };

struct X : s1 { operator TYPE() const { return s1::x; } };
struct XX : s2 { operator VECTOR2<TYPE>() const { return VECTOR2<TYPE>(s2::x, s2::x); } };
struct XXX : s3 { operator VECTOR3<TYPE>() const { return VECTOR3<TYPE>(s3::x, s3::x, s3::x); } };
struct XXXX : s4 { operator VECTOR4<TYPE>() const { return VECTOR4<TYPE>(s4::x, s4::x, s4::x, s4::x); } };
public:
VECTOR4() {}
VECTOR4(const TYPE& x, const TYPE& y, const TYPE& z, const TYPE& w) { v.x = x; v.y = y; v.z = z; v.w = w; }

X x;
XX xx;
XXX xxx;
XXXX xxxx;

// Overload for cout
friend ostream& operator<<(ostream& os, const VECTOR4& toString)
{
os << "(" << toString.v.x << ", " << toString.v.y << ", " << toString.v.z << ", " << toString.v.w << ")";
return os;
}
friend ostream& operator<<(ostream& os, const VECTOR2<TYPE>& toString);
friend ostream& operator<<(ostream& os, const VECTOR3<TYPE>& toString);
};

// Test code
int main (int argc, char * const argv[])
{
vec2 my2dVector(1, 2);

cout << my2dVector.x << endl;
cout << my2dVector.xx << endl;
cout << my2dVector.xxx << endl;
cout << my2dVector.xxxx << endl;

vec3 my3dVector(3, 4, 5);

cout << my3dVector.x << endl;
cout << my3dVector.xx << endl;
cout << my3dVector.xxx << endl;
cout << my3dVector.xxxx << endl;

vec4 my4dVector(6, 7, 8, 9);

cout << my4dVector.x << endl;
cout << my4dVector.xx << endl;
cout << my4dVector.xxx << endl;
cout << my4dVector.xxxx << endl;

return 0;
}

代码工作并产生正确的输出,但我更喜欢尽可能没有警告的代码。我听从了编译器给我的建议(summarized here 并被论坛和 StackOverflow 描述为对这个警告的回答)并添加了两个据称可以告诉编译器发生了什么的事情。也就是说,我在模板 union 的预定义之后添加了函数定义作为非友元:

template <typename TYPE> ostream& operator<<(ostream& os, const VECTOR2<TYPE>& toString);
template <typename TYPE> ostream& operator<<(ostream& os, const VECTOR3<TYPE>& toString);
template <typename TYPE> ostream& operator<<(ostream& os, const VECTOR4<TYPE>& toString);

并且,对于导致问题的每个友元函数,我都添加了 <>在函数名称之后,例如 VECTOR2 的情况:

friend ostream& operator<< <> (ostream& os, const VECTOR3<TYPE>& toString);
friend ostream& operator<< <> (ostream& os, const VECTOR4<TYPE>& toString);

但是,这样做会导致错误,例如:

LINE 139: error: no match for 'operator<<' in 'std::cout << my2dVector.VECTOR2<float>::xxx'

这是怎么回事?是与这些模板化的类似 union 类的结构如何相互关联有关,还是归因于 union 本身?

更新

在重新思考涉及的问题并听取了Pot​​atoswatter的各种建议后,我找到了最终的解决方案。与互联网上几乎每个 cout 重载示例不同,我不需要访问私有(private)成员信息,但可以使用公共(public)接口(interface)来执行我想做的事情。因此,我创建了一个非友元重载函数,该函数内联用于调用真正友元重载函数的调配部分。这绕过了编译器在模板化友元函数方面的问题。我已经添加到我的项目的最新版本中。它现在适用于我尝试过的两个版本的 GCC,没有任何警告。有问题的代码如下所示:

template <typename SWIZZLE> inline
typename EnableIf< Is2D< typename SWIZZLE::PARENT >, ostream >::type&
operator<<(ostream& os, const SWIZZLE& printVector)
{
os << (typename SWIZZLE::PARENT(printVector));
return os;
}

template <typename SWIZZLE> inline
typename EnableIf< Is3D< typename SWIZZLE::PARENT >, ostream >::type&
operator<<(ostream& os, const SWIZZLE& printVector)
{
os << (typename SWIZZLE::PARENT(printVector));
return os;
}

template <typename SWIZZLE> inline
typename EnableIf< Is4D< typename SWIZZLE::PARENT >, ostream >::type&
operator<<(ostream& os, const SWIZZLE& printVector)
{
os << (typename SWIZZLE::PARENT(printVector));
return os;
}

最佳答案

您不能声明免费 friend仅在类模板中。除非在全局范围内明确声明,否则该定义在类外部不可见。 (编辑:这段代码是一个异常(exception); friend 们在 main 中被 ADL 找到。但是,我不明白为什么他们没有被 ADL 在其他模板中找到……)所以,例如,在关闭模板之后VECTOR2 的大括号, 添加原型(prototype)

template< class TYPE >
ostream& operator<<(ostream& os, const VECTOR2<TYPE>& toString);

除此之外,friend你现在有因为裸原型(prototype)对我来说看起来没有必要。和 s1s4看起来显然是多余的。我无法辨别整件事的意图。

更正

在这种情况下,免费的 friend由于隐式转换的方式不能成为模板 operator s被使用。所以上面的声明不会匹配 VECTOR 中的非模板声明。模板。通过友元机制由模板生成非模板函数是一种奇怪而棘手的语言特性,在这里可以正确使用,回旋余地很小。最好的选择是禁用警告,而不是尝试重构复杂的重载解决方案。

更新

其实这里有一个简单的重构。只需添加 operator<<到 swizzle 类以及隐式转换运算符。 (抱歉格式草率。)

#include <iostream> // cout, endl
#include <sstream> // ostream, ostringstream, string

using std::cout;
using std::endl;
using std::string;
using std::ostream;

// Predefines
template <typename TYPE> union VECTOR2;
template <typename TYPE> union VECTOR3;
template <typename TYPE> union VECTOR4;

typedef VECTOR2<float> vec2;
typedef VECTOR3<float> vec3;
typedef VECTOR4<float> vec4;

template< class TYPE2 >
ostream& operator<<(ostream& os, const VECTOR2<TYPE2>& toString)
{
os << "(" << toString.v.x << ", " << toString.v.y << ")";
return os;
}

template <typename TYPE>
union VECTOR2
{
private:
struct { TYPE x, y; } v;

struct s1 { protected: TYPE x, y; };
struct s2 { protected: TYPE x, y; };
struct s3 { protected: TYPE x, y; };
struct s4 { protected: TYPE x, y; };

struct X : s1 { operator TYPE() const { return s1::x; } };
struct XX : s2 { operator VECTOR2<TYPE>() const { return VECTOR2<TYPE>(s2::x, s2::x); }
friend ostream& operator<<( ostream &os, XX const &v ) { os << VECTOR2<TYPE>( v ); } };
struct XXX : s3 { operator VECTOR3<TYPE>() const { return VECTOR3<TYPE>(s3::x, s3::x, s3::x); }
friend ostream& operator<<( ostream &os, XXX const &v ) { os << VECTOR3<TYPE>( v ); } };
struct XXXX : s4 { operator VECTOR4<TYPE>() const { return VECTOR4<TYPE>(s4::x, s4::x, s4::x, s4::x); }
friend ostream& operator<<( ostream &os, XXXX const &v ) { os << VECTOR4<TYPE>( v ); } };
public:
VECTOR2() {}
VECTOR2(const TYPE& x, const TYPE& y) { v.x = x; v.y = y; }

X x;
XX xx;
XXX xxx;
XXXX xxxx;

// Overload for cout
friend ostream& operator<< <>(ostream& os, const VECTOR2<TYPE>& toString);
};

template< class TYPE >
ostream& operator<<(ostream& os, const VECTOR3<TYPE>& toString)
{
os << "(" << toString.v.x << ", " << toString.v.y << ", " << toString.v.z << ")";
return os;
}

template <typename TYPE>
union VECTOR3
{
private:
struct { TYPE x, y, z; } v;

struct s1 { protected: TYPE x, y, z; };
struct s2 { protected: TYPE x, y, z; };
struct s3 { protected: TYPE x, y, z; };
struct s4 { protected: TYPE x, y, z; };

struct X : s1 { operator TYPE() const { return s1::x; } };
struct XX : s2 { operator VECTOR2<TYPE>() const { return VECTOR2<TYPE>(s2::x, s2::x); }
friend ostream& operator<<( ostream &os, XX const &v ) { os << VECTOR2<TYPE>( v ); } };
struct XXX : s3 { operator VECTOR3<TYPE>() const { return VECTOR3<TYPE>(s3::x, s3::x, s3::x); }
friend ostream& operator<<( ostream &os, XXX const &v ) { os << VECTOR3<TYPE>( v ); } };
struct XXXX : s4 { operator VECTOR4<TYPE>() const { return VECTOR4<TYPE>(s4::x, s4::x, s4::x, s4::x); }
friend ostream& operator<<( ostream &os, XXXX const &v ) { os << VECTOR4<TYPE>( v ); } };
public:
VECTOR3() {}
VECTOR3(const TYPE& x, const TYPE& y, const TYPE& z) { v.x = x; v.y = y; v.z = z; }

X x;
XX xx;
XXX xxx;
XXXX xxxx;

// Overload for cout
friend ostream& operator<< <>(ostream& os, const VECTOR3<TYPE>& toString);
};

template< class TYPE >
ostream& operator<<(ostream& os, const VECTOR4<TYPE>& toString)
{
os << "(" << toString.v.x << ", " << toString.v.y << ", " << toString.v.z << ", " << toString.v.w << ")";
return os;
}

template <typename TYPE>
union VECTOR4
{
private:
struct { TYPE x, y, z, w; } v;

struct s1 { protected: TYPE x, y, z, w; };
struct s2 { protected: TYPE x, y, z, w; };
struct s3 { protected: TYPE x, y, z, w; };
struct s4 { protected: TYPE x, y, z, w; };

struct X : s1 { operator TYPE() const { return s1::x; } };
struct XX : s2 { operator VECTOR2<TYPE>() const { return VECTOR2<TYPE>(s2::x, s2::x); }
friend ostream& operator<<( ostream &os, XX const &v ) { os << VECTOR2<TYPE>( v ); } };
struct XXX : s3 { operator VECTOR3<TYPE>() const { return VECTOR3<TYPE>(s3::x, s3::x, s3::x); }
friend ostream& operator<<( ostream &os, XXX const &v ) { os << VECTOR3<TYPE>( v ); } };
struct XXXX : s4 { operator VECTOR4<TYPE>() const { return VECTOR4<TYPE>(s4::x, s4::x, s4::x, s4::x); }
friend ostream& operator<<( ostream &os, XXXX const &v ) { os << VECTOR4<TYPE>( v ); } };
public:
VECTOR4() {}
VECTOR4(const TYPE& x, const TYPE& y, const TYPE& z, const TYPE& w) { v.x = x; v.y = y; v.z = z; v.w = w; }

X x;
XX xx;
XXX xxx;
XXXX xxxx;

// Overload for cout
friend ostream& operator<< <>(ostream& os, const VECTOR4& toString);
};

// Test code
int main (int argc, char * const argv[])
{
vec2 my2dVector(1, 2);

cout << my2dVector.x << endl;
cout << my2dVector.xx << endl;
cout << my2dVector.xxx << endl;
cout << my2dVector.xxxx << endl;

vec3 my3dVector(3, 4, 5);

cout << my3dVector.x << endl;
cout << my3dVector.xx << endl;
cout << my3dVector.xxx << endl;
cout << my3dVector.xxxx << endl;

vec4 my4dVector(6, 7, 8, 9);

cout << my4dVector.x << endl;
cout << my4dVector.xx << endl;
cout << my4dVector.xxx << endl;
cout << my4dVector.xxxx << endl;

return 0;
}

很奇怪,我添加的函数仍然是在模板中定义的非模板 friend ,与我删除的函数非常相似。但无论出于何种原因,GCC 都不会提示它们。如果是这样,您可以使它们成为模板并将它们移到适当的命名空间范围之外。

顺便说一下,与原始代码相比,我个人并不喜欢此代码。如果我是你,我只会禁用警告。

关于c++ - 模板化 << friend 在与其他模板化 union 类型相互关联时不工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3489619/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com