C++:友好模板参数的模板类型成员的正确语法?
C++: Correct syntax for friending a template type member of template parameter?
我有一个采用模板类型参数 (tTRAIT) 的 class。我想将 tTRAIT 的模板 type member alias 添加为朋友,但我无法弄清楚句法。 (这甚至可能吗?)。
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
,但似乎没有帮助。
作为一个丑陋的 hack(仅适用于 bool 参数),我可以通过手动为每个专业化添加好友来使其工作。
friend typename tTRAIT::template TFoo<false>;
friend typename tTRAIT::template TFoo<true >;
但这太恶心了。
有谁知道该怎么做,或者是否可以这样做?
我认为这是不可能的。来自标准草案 N4296:
§ 14.5.4/1 [temp.friend]
A friend of a class or class template can be a function template or class template, a specialization of a
function template or class template, or a non-template function or class.
这不包括别名模板,因此该标准不支持您想要执行的操作。这可能是由于以下摘录(强调我的):
§ 14.5.7/1 [temp.alias]
A template-declaration in which the declaration is an alias-declaration (Clause 7) declares the identifier to
be a alias template. An alias template is a name for a family of types.
别名模板命名一个单独的类型系列,因此即使有一些对此有意义的语法,您也会将别名模板而不是被别名的模板加为好友。
例如,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] : friend struct 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 接受 ...
我有一个采用模板类型参数 (tTRAIT) 的 class。我想将 tTRAIT 的模板 type member alias 添加为朋友,但我无法弄清楚句法。 (这甚至可能吗?)。
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
,但似乎没有帮助。
作为一个丑陋的 hack(仅适用于 bool 参数),我可以通过手动为每个专业化添加好友来使其工作。
friend typename tTRAIT::template TFoo<false>;
friend typename tTRAIT::template TFoo<true >;
但这太恶心了。
有谁知道该怎么做,或者是否可以这样做?
我认为这是不可能的。来自标准草案 N4296:
§ 14.5.4/1 [temp.friend]
A friend of a class or class template can be a function template or class template, a specialization of a function template or class template, or a non-template function or class.
这不包括别名模板,因此该标准不支持您想要执行的操作。这可能是由于以下摘录(强调我的):
§ 14.5.7/1 [temp.alias]
A template-declaration in which the declaration is an alias-declaration (Clause 7) declares the identifier to be a alias template. An alias template is a name for a family of types.
别名模板命名一个单独的类型系列,因此即使有一些对此有意义的语法,您也会将别名模板而不是被别名的模板加为好友。
例如,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] : friend struct 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 接受 ...