我知道默认情况下编译器不能看到"依赖名称".但是我在回答其他SO问题(这里,在这里,最终在C++ faq)时被告知using声明可能有所帮助.
所以我试过了.
模板基类:
// regardless of the fact that members are exposed...
template<typename T>
struct TBase {
typedef T MemberType;
MemberType baseMember;
MemberType baseFunction() { return MemberType(); }
};
Run Code Online (Sandbox Code Playgroud)
和派生类,使用基数的成员:
template<typename T>
struct TDerived : public TBase<T> {
// http://www.parashift.com/c++-faq-lite/nondependent-name-lookup-members.html
// tells us to use a `using` declaration.
using typename TBase<T>::MemberType;
using TBase<T>::baseFunction;
using TBase<T>::baseMember;
void useBaseFunction() {
// this goes allright.
baseFunction();
++baseMember;
// but here, the compiler doesn't want …Run Code Online (Sandbox Code Playgroud) 有谁知道为什么使用声明似乎不适用于从依赖基类导入类型名称?它们适用于成员变量和函数,但至少在GCC 4.3中,它们似乎被忽略了类型.
template <class T>
struct Base
{
typedef T value_type;
};
template <class T>
struct Derived : Base<T>
{
// Version 1: error on conforming compilers
value_type get();
// Version 2: OK, but unwieldy for repeated references
typename Base<T>::value_type get();
// Version 3: OK, but unwieldy for many types or deep inheritance
typedef typename Base<T>::value_type value_type;
value_type get();
// Version 4: why doesn't this work?
using typename Base<T>::value_type;
value_type get(); // GCC: `value_type' is not a type
};
Run Code Online (Sandbox Code Playgroud)
我有一个基类,有一组allocator样式的typedef,我想在几个继承级别继承.到目前为止,我发现的最佳解决方案是上面的版本3,但我很好奇为什么版本4似乎不起作用.GCC接受使用声明,但似乎忽略它. …
可以编译以下代码而不会出现错误:
template <typename T> struct A {
void f() { this->whatever; } // whatever is not declared before
};
int main() {
A<int> a;
}
Run Code Online (Sandbox Code Playgroud)
我知道这是因为this是一个依赖于类型的表达式,它使名称查找whatever被推迟,直到知道实际的模板参数.由于f()在这种情况下从不使用成员函数,因此不A<T>::f存在实例化,并且whatever永远不会执行名称查找.
我可以理解,this如果类模板具有依赖于类型的基类,那么它是类型相关的:
template <typename T> struct B { T whatever; };
template <typename T> struct A : B<T> {
void f() { this->whatever; }
};
int main() {
A<int> a;
}
Run Code Online (Sandbox Code Playgroud)
在解析模板类的定义时A,不可能知道它的基类是什么,这使得this->whatever潜在合法(B<T>可能有一个成员命名whatever).相反,this->whatever一旦在f …
这个问题的灵感来自另一个问题.在尝试回答这个问题时,我明白自己有很多问题.所以......考虑以下几点:
struct S1
{
enum { value = 42 };
};
template <class T> struct S2
{
typedef S1 Type;
};
template <class T> struct S3
{
typedef S2<T> Type;
};
template <class T> struct S4
{
typedef typename T::Type::Type Type; //(1)//legal?
enum {value = T::Type::Type::value }; //(2)//legal?
};
int main()
{
S4<S3<S2<S2<S1> > > >::value;
}
Run Code Online (Sandbox Code Playgroud)
这与MSVC9.0和Online Comeau成功编译.但是,困扰我的是我不理解typename(1)中提到的内容以及为什么我们不需要typename(2).
我已经尝试过这两种语法(合成器?),我认为它应该是MSVC上的两种失败:
typedef typename T::typename Type::Type Type;
enum {value = typename T::typename Type::Type::value };
Run Code Online (Sandbox Code Playgroud)
和 …
I have been reading about removing reference of a type, here.
It gives the following example:
#include <iostream> // std::cout
#include <type_traits> // std::is_same
template<class T1, class T2>
void print_is_same() {
std::cout << std::is_same<T1, T2>() << '\n';
}
int main() {
std::cout << std::boolalpha;
print_is_same<int, int>();
print_is_same<int, int &>();
print_is_same<int, int &&>();
print_is_same<int, std::remove_reference<int>::type>(); // Why not typename std::remove_reference<int>::type ?
print_is_same<int, std::remove_reference<int &>::type>();// Why not typename std::remove_reference<int &>::type ?
print_is_same<int, std::remove_reference<int &&>::type>();// Why not typename std::remove_reference<int &&>::type ?
} …Run Code Online (Sandbox Code Playgroud) 我有以下代码:
template <typename TC>
class C
{
struct S
{
template <typename TS>
void fun() const
{}
};
void f(const S& s)
{
s.fun<int>();
}
};
// Dummy main function
int main()
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当使用 gcc 9.2 和 clang (9.0) 构建它时,由于template调用fun. Clang 显示:
error: use 'template' keyword to treat 'fun' as a dependent template name
s.fun<int>();
^
template
Run Code Online (Sandbox Code Playgroud)
我不明白为什么编译器认为fun是 上下文中的依赖名称f,因为f它本身不是模板。如果我改为C普通类而不是模板,错误就会消失;但是,我不明白为什么首先应该出现错误,因为既不S也不f依赖于TC. …
template <class T>
void Yeap(T);
int main() {
Yeap(0);
return 0;
}
template <class T>
void YeapImpl();
struct X;
template <class T>
void Yeap(T) {
YeapImpl<X>(); // pass X to another template
}
template <class T>
void YeapImpl() {
T().foo();
}
struct X {
void foo() {}
};
Run Code Online (Sandbox Code Playgroud)
请注意,struct X直到最后才定义.我曾经相信所有使用过的名字必须在实例化时完成.但是在这里,编译器如何在定义之前将其视为完整类型?
我已经检查了cppreference中的依赖名称和函数模板实例化的绑定规则和查找规则,但是没有一个能够解释这里发生的事情.
考虑到以下代码示例,我希望必须template在此处使用关键字来指导编译器将变量视为v模板。然而,MSVC 拒绝使用该template关键字,而 Clang 和 GCC 实际上需要它。在这种情况下,C++20 标准中的哪条具体规则强制或禁止使用关键字template?
struct s {
template<typename...>
static constexpr auto v = true;
};
// all ok
static_assert([](auto x){ return decltype(x)::template v<>; }(s{}));
// clang ok, gcc ok, msvc nope
static_assert([](auto x){ return x.template v<>; }(s{}));
// clang nope, gcc nope, msvc ok
static_assert([](auto x){ return x.v<>; }(s{}));
Run Code Online (Sandbox Code Playgroud)
来自 Clang 的错误消息:
<source>:10:36: error: use 'template' keyword to treat 'v'
as a dependent template name
10 | static_assert([](auto …Run Code Online (Sandbox Code Playgroud) C++ 11标准的N3337草案声明 [namespace.udecl]
using声明在声明区域中引入了一个名称,其中出现using声明.
每个using声明都是声明和成员声明,因此可以在类定义中使用.
在用作成员声明的using声明中,嵌套名称说明符应命名要定义的类的基类.
这通常用于在派生类的基类public中创建受保护的typedef,如下例所示,它在最新版本的Clang中成功编译:
struct A
{
protected:
typedef int Type;
};
struct B : A
{
using A::Type;
};
B::Type x;
Run Code Online (Sandbox Code Playgroud)
using-declaration可以引用模板类.这编译:
struct A
{
protected:
template<typename T>
struct Type
{
};
};
struct B : A
{
using A::Type;
};
B::Type<int> x;
Run Code Online (Sandbox Code Playgroud)
也可以引用依赖基类中的模板.以下编译成功(使用typedef注释.)
template<typename T>
struct A
{
protected:
template<typename U>
struct Type
{
};
};
template<typename T>
struct B : A<T>
{
using /* typename */ A<T>::Type; // A<T> is dependent, typename required?
// …Run Code Online (Sandbox Code Playgroud) c++ templates dependent-name using-declaration language-lawyer
模板中使用的从属名称的查找被推迟到知道模板参数为止,这时ADL会检查具有外部链接的函数声明,这些声明从模板定义上下文或模板实例化上下文中可见。
与此相反,以下代码片段可以使用三个编译器(MSVC,clang和gcc)很好地进行编译:
template <class T>
void CallFoo ()
{
Foo (T ());
}
class Apple {};
int main ()
{
CallFoo<Apple> ();
}
static void Foo (Apple)
{
}
Run Code Online (Sandbox Code Playgroud)
Foo是以下内容中的从属名称CallFoo:它取决于模板参数T。但是,Foo尽管违反了上面引用的两个规则,但是编译器仍然可以找到该函数。
Foo从的定义或实例中都看不到的声明CallFoo,因为它位于两者之下。Foo 有内部联系。这三个编译器都不可能有错误。我可能误会了一些东西。您能详细说明一下吗?
c++ linkage dependent-name language-lawyer argument-dependent-lookup
c++ ×10
dependent-name ×10
templates ×8
c++11 ×1
c++17 ×1
c++20 ×1
compiler-bug ×1
linkage ×1
type-traits ×1
typedef ×1
typename ×1