对于模板,我看到了两个声明:
template < typename T >
template < class T >
Run Code Online (Sandbox Code Playgroud)
有什么不同?
这些关键字在下面的例子中究竟是什么意思(取自德国维基百科关于模板的文章)?
template < template < typename, typename > class Container, typename Type >
class Example
{
Container< Type, std::allocator < Type > > baz;
};
Run Code Online (Sandbox Code Playgroud) 对于许多问题,答案似乎可以在"标准"中找到.但是,我们在哪里找到它?最好是在线.
谷歌搜索有时会觉得徒劳,尤其是对于C标准,因为他们在编程论坛的大量讨论中被淹没.
要开始这个,因为这些是我现在正在搜索的,那里有很好的在线资源:
我正在尝试存储std::tuple不同数量的值,这些值稍后将用作调用与存储类型匹配的函数指针的参数.
我创建了一个简化的示例,显示了我正在努力解决的问题:
#include <iostream>
#include <tuple>
void f(int a, double b, void* c) {
std::cout << a << ":" << b << ":" << c << std::endl;
}
template <typename ...Args>
struct save_it_for_later {
std::tuple<Args...> params;
void (*func)(Args...);
void delayed_dispatch() {
// How can I "unpack" params to call func?
func(std::get<0>(params), std::get<1>(params), std::get<2>(params));
// But I *really* don't want to write 20 versions of dispatch so I'd rather
// write something like:
func(params...); // Not legal
}
}; …Run Code Online (Sandbox Code Playgroud) c++ function-pointers variadic-templates c++11 iterable-unpacking
有时我看到gcc在使用模板时吐出的一些非常难以理解的错误消息......具体来说,我遇到了一些问题,看似正确的声明引起了非常奇怪的编译错误,通过在"typename"关键字前加上前缀而神奇地消失了声明的开头...(例如,就在上周,我宣布两个迭代器作为另一个模板化类的成员,我必须这样做)...
关于typename的故事是什么?
在C++头文件中,我看到这段代码:
typedef typename _Mybase::value_type value_type;
Run Code Online (Sandbox Code Playgroud)
现在,据我所知,引用Schildt撰写的" C++完整参考文献 ".typename可以用关键字类代替,第二个用途typename是通知编译器模板声明中使用的名称是类型名而不是对象名.
同样,您可以使用关键字定义新的数据类型名称typedef.您实际上并未创建新数据类型,而是为现有类型定义新名称.
但是,您能否准确解释上述代码行的含义,在哪里typedef和typename哪些结合在一起.::声明中的" "是什么意思?
考虑以下代码:
template<class K>
class C {
struct P {};
vector<P> vec;
void f();
};
template<class K> void C<K>::f() {
typename vector<P>::iterator p = vec.begin();
}
Run Code Online (Sandbox Code Playgroud)
为什么此示例中需要"typename"关键字?是否还有其他必须指定"typename"的情况?
我遇到了一段奇怪的代码:
#include <iostream>
template <int N>
struct Collection {
int data[N];
Collection() {
for(int i = 0; i < N; ++i) {
data[i] = 0;
}
};
void SetValue(int v) {
for(int i = 0; i < N; ++i) {
data[i] = v;
}
};
template <int I>
int GetValue(void) const {
return data[I];
};
};
template <int N, int I>
void printElement(Collection<N> const & c) {
std::cout << c.template GetValue<I>() << std::endl; /// doesn't compile without ".template" …Run Code Online (Sandbox Code Playgroud) 这不编译:
template<class X> struct A {
template<int I> void f() {}
};
template<class T> void g()
{
A<T> a;
a.f<3>(); // Compilation fails here (Line 18)
}
int main(int argc, char *argv[])
{
g<int>(); // Line 23
}
Run Code Online (Sandbox Code Playgroud)
编译器(gcc)说:
hhh.cpp:在函数'void g()'中:
hhh.cpp:18:错误:')'令牌之前的预期primary-expression
hhh.cpp:在函数'void g()[with T = int]'中:
hhh.cpp:23:从这里实例化
hhh.cpp:18:错误:无效使用成员(你忘了'&'?)
谁能解释为什么会这样?有没有办法让它发挥作用?
我非常清楚为什么需要使用typename依赖类型,因为当它看到类似的东西时,编译器可能无法消除类型和变量声明之间的歧义T::type,请参阅此答案以获得一个很好的解释.TL; DR:在类似的表达式中T::type * x;,编译器不能"知道" T::type是某个类型,还是在某个特定的特化中声明的变量T.
但是,在类似的东西
using type = T::type;
Run Code Online (Sandbox Code Playgroud)
没有任何暧昧.IMO T::type 应该始终被解析为一个类型,因为它是using语句的RHS的一部分.但是,我们仍然需要在typename这里使用(至少根据gcc和clang),
using type = typename T::type;
Run Code Online (Sandbox Code Playgroud)
Live on Coliru, gcc Live on Coliru, clang
Visual C++ 似乎接受了没有a 的代码typename,但是我对编译器完全符合标准没有太多信心(实际上,它有许多非标准扩展,例如将rvalues绑定到非const引用).
问:有什么理由说这不是typenameC++ 11及更高版本规则的例外吗?
为什么std::stack和std::queue使用类型模板参数,而不是模板的模板参数为他们的基础容器类型?
即为什么stack声明如下:
template<typename T, typename Container = deque<T>>
class stack;
Run Code Online (Sandbox Code Playgroud)
但不是这样的:
template<typename T, template<typename> class Container = deque>
class stack;
Run Code Online (Sandbox Code Playgroud)
?