C++:将模板参数的模板类型成员加为好友的语法正确吗

C++: Correct syntax for friending a template type member of template parameter?

本文关键字:语法 好友 类型 参数 C++ 成员      更新时间:2023-10-16

我有一个类,它接受模板类型参数(tTRAIT)。我想成为tTRAIT的模板类型成员别名的好友,但我搞不清语法。(这可能吗?)。

template <bool bBOOL>
struct SFoo {};
struct STrait
{
template <bool bBOOL>
using TFoo = SFoo<bBOOL>;
};
template <typename tTRAIT>
struct SBar
{
template <bool bBOOL>
friend typename tTRAIT::template TFoo<bBOOL>;
};
SBar<STrait> bar;

Clang的错误(在friend线上)是:

error: friend type templates must use an elaborated type

我试过用尽我能想到的所有可能的组合:

friend tTRAIT::TFoo;
friend tTRAIT::template TFoo;
friend typename tTRAIT::TFoo;
friend typename tTRAIT::template TFoo;
template <bool bBOOL> friend tTRAIT::TFoo;
template <bool bBOOL> friend tTRAIT::TFoo<bBOOL>;
template <bool bBOOL> friend tTRAIT::template TFoo;
template <bool bBOOL> friend tTRAIT::template TFoo<bBOOL>;
template <bool bBOOL> friend typename tTRAIT::TFoo;
template <bool bBOOL> friend typename tTRAIT::TFoo<bBOOL>;
template <bool bBOOL> friend typename tTRAIT::template TFoo;
template <bool bBOOL> friend typename tTRAIT::template TFoo<bBOOL>;

我也尝试过使用using,但似乎没有帮助。

作为一个丑陋的破解(只适用于bool参数),我可以通过手动为每个专业化添加好友来让它发挥作用。

friend typename tTRAIT::template TFoo<false>;
friend typename tTRAIT::template TFoo<true >;

但这太恶心了。

有人知道如何做到这一点吗,或者这是否可以做到?

我认为这是不可能的。来自标准草案N4296:

§14.5.4/1[临时朋友]

类或类模板的朋友可以是函数模板或类模板函数模板或类模板,或非模板函数或类。

这不包括别名模板,因此标准不支持您想要做的事情。这可能是由于以下摘录(强调我的):

§14.5.7/1[临时别名]

一个模板声明,其中声明是一个别名声明(第7条)将标识符声明为是一个别名模板别名模板是一个类型族的名称

别名模板命名一个单独的类型族,因此即使有一些语法对此有意义,您也会将别名模板而不是正在别名化的模板作为好友。

例如,GCC会编译这个(Clang不会),但你实际上无法以任何合理的方式使用友谊:

template <bool B>
using MyTFoo = typename tTRAIT::template TFoo<B>;
template <bool> friend class MyTFoo; 

别名模板与别名模板不同的另一个示例:

template <template <typename...> class A, template <typename...> class B>
struct is_same_template : std::false_type{};
template <template <typename...> class A>
struct is_same_template<A,A> : std::true_type{};
template <typename T> using myvec = std::vector<T>;
//this fails
static_assert(is_same_template<myvec,std::vector>::value, "wat");

使用显式实例化的手动好友关系将起作用,因为别名模板将塌陷为与别名模板完全相同的类型。类似的例子:

//this passes!
static_assert(std::is_same<myvec<int>,std::vector<int>>::value, "wat");

我可以在std=c++11模式下使用Clang 3.4.1。

此编译没有错误:

模板

struct SBar
{
private:
int j;
public:
template <bool bBOOL>
friend struct tTRAIT::TFoo;
void setJ(int j) {
this->j = j;
}
};

但是。。。我收到以下警告:警告:不支持友元模板声明的依赖嵌套名称说明符"tTRAIT::";忽略此好友声明[-Wunsupported friend]:好友结构tTRAIT::TFoo

并且我可以确认SFoo类不是朋友(private j的原因…)

我唯一可以编译和运行它的方法是:

struct SBar
{
private:
int j;
public:
template <bool bBOOL>
friend struct sFoo;
void setJ(int j) {
this->j = j;
}
};

很好,SFoo的朋友,但它在一定程度上违反了OP要求([模板参数]的模板类型成员)。。。

我目前无法访问最近的gcc,但我认为我们正处于编译器如何解释该标准的边缘。我阅读了TartanLlama引用的章节,但无法确定这是否是有意的。也许我的第一次尝试会被gcc接受。。。