nested-name-specifier
The typename
is not needed there, and is therefore not allowed.
MSVC do not parse templates properly until they are actually used, so some errors are not found until later.
typename keyword and nested name specifier
As @MikeSeymour's answer explains, going strictly by the standard (C++11, I don't have a C++14 text on hand), case (1) should actually be erroneous as well - typename
prefixing a qualified name can only be used when there's at least one name on the left-hand side of the ::
.
However, as pointed out by @hvd in the comments, CWG issue 382 indicates the actual intent is to allow typename
before any qualified name, including global-namespace qualification. Since this is what most compilers seem to implement, the rest of this answer follows with this idea.
When viewed like this, it's not that case (2) is a restriction, it's that case (1) is benevolence. The required rule (and its very original wording, I believe) is basically that "if a qualified name which depends on template parameters denotes a type, you must prefix it with typename
." For convenience, it is loosened to "typename
can be used for any qualified name which dentoes a type, whether it's dependent or not."(1)
In contrast, an unqualified name can never be ambiguous as to whether it refers to a type or not, so it never requires typename
and typename
is therefore not allowed there.
(1)This loosening is not really explicitly stated in the standard, but follows from the combination of several rules. Basically, wherever a simple-type-specifier (something which denotes a type) is allowed, the grammar also allows a typename-specifier (a qualified name prefixed with typename
). The rules for templates (mainly in 14.6) only state that typename
is required when a dependent qualified name denotes a type. Since nothing forbids typename
in other contexts, it can be used with any qualified name which denotes a type (even outside of template context).
Using a nested name specifier in CRTP
impl_t
is an incomplete type in base
. You can solve the problem either using another template parameter or using a type traits technique:
template<class>
struct traits;
template<>
struct traits<deriv_t>
{
static constexpr std::size_t i_q = 1;
};
...
void print () {
std::cout << "Base, i_q = " << traits<impl_t>::i_q << std::endl;
}
using vec_t = std::array<double, traits<impl_t>::i_q>;
You don't have complaints in print()
because at the point of its instantiation impl_t
becomes a complete type.
error: nested name specifier for declaration does not refer into a class, class template or class template partial specialization
As I found out from my colleagues. C++ is a pretty funny language. Mainly due to its long history.
The meaning of the compilation error is that the problematic line of code: h::test (h::TYPE::A);
The compiler parsed as "creating a variable of type h::test with the name h::TYPE::A". And then the compiler goes crazy, because you can't call variables that way.
All this is because someone once decided that it might be convenient to declare variables in this
int (value) style;
value = 42;
std::string (str);
str = "hello";
In other cases, the compiler parses the code correctly - it understands that this is a call to the constructor of the h::text class.
Clang error: Dependent nested name specifier for friend class declaration not supported
You can change the friend
declaration only valid for the Base
of current template parameter T
, i.e. current instantiation.
template<typename T>
class Base {
std::set<int> data_;
public:
Base(const std::set<int>& data): data_{data} {}
friend std::size_t
std::hash<Base<T>>::operator()(const Base<T>& b) const noexcept;
//or just
//friend std::size_t
//std::hash<Base>::operator()(const Base& b) const noexcept;
};
Note that the effect is different with yours. With the above friend
declaration, for example, given Base<int>
, only std::hash<Base<int>>::operator()
is the friend
. With template friend
declaration in your code, given Base<int>
, all the possible instantiations like std::hash<Base<int>>::operator()
, std::hash<Base<char>>::operator()
, ... are friend
s.
Related Topics
How to Increment an Iterator by Just Adding a Number
Pair<Int,Int> Pair as Key of Unordered_Map Issue
Does Throw Inside a Catch Ellipsis (...) Rethrow the Original Error in C++
Same Class Name in Different C++ Files
Can Branches with Undefined Behavior Be Assumed Unreachable and Optimized as Dead Code
How to Pass Multiple Ints into a Vector at Once
Vc++ Fatal Error Lnk1168: Cannot Open Filename.Exe for Writing
What Is a "Regular Type" in the Context of Move Semantics
How to Read a File into Vector in C++
Why and How to Use Namespaces in C++
Are There Any Downsides to Using Upx to Compress a Windows Executable
Initializing Container of Unique_Ptrs from Initializer List Fails with Gcc 4.7
Why Was Std::Strstream Deprecated
Confusion About Pointers and References in C++
C++ Template Metaprogramming - How to Output the Generated Code