以下代码有什么问题?
template<typename X>
struct A {
template<int N>
int foo() const {
return N;
}
};
template<typename X>
struct B {
int bar(const A<X>& v) {
return v.foo<13>();
}
};
#include <iostream>
using std::cout;
using std::endl;
int main() {
A<double> a;
B<double> b;
cout << b.bar(a) << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在函数内部,B::bar编译器抱怨:
错误:类型''和'int'到二进制'operator <'的操作数无效
如果A不是模板,那么一切都很好.
假设我有一个模板函数(例如foo),它返回一个const依赖类型.用于限定返回类型的选项const是将const放在typename关键字的左侧:
template<typename T>
const typename T::bar
^^^^^
foo(T const& baz) {
...
}
Run Code Online (Sandbox Code Playgroud)
或在依赖类型的右侧:
template<typename T>
typename T::bar const
^^^^^
foo(T const& baz) {
...
}
Run Code Online (Sandbox Code Playgroud)
但是如果我将const限定符放在typename关键字和依赖类型之间呢?
template<typename T>
typename const T::bar
^^^^^
foo(T const& baz) {
...
}
Run Code Online (Sandbox Code Playgroud)
如上所述,无法为GCC和CLANG编译,但令我惊讶的是VC++编译得很好.
const在这样的上下文中放置限定符的适当位置?今天我的一位朋友告诉我,以下代码在他的Visual Studio 2008上编译得很好:
#include <vector>
struct A
{
static int const const_iterator = 100;
};
int i;
template <typename T>
void PrintAll(const T & obj)
{
T::const_iterator *i;
}
int main()
{
std::vector<int> v;
A a;
PrintAll(a);
PrintAll(v);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我通常使用g ++,它总是拒绝传递第二个PrintAll()调用.据我所知,对于这个问题,g ++正在以标准的方式翻译模板.
那么,我的知识是错误的,还是VS2008的扩展?
在a.hpp我定义:
#include <utility>
namespace Board {
template<int W, int H>
struct GroupNode
{
using PointType = std::pair<int, int>;
// ...
};
}
Run Code Online (Sandbox Code Playgroud)
然后,在b.cpp我定义:
#include "a.hpp"
namespace Board {
template<int W, int H>
struct NodeList
{
using StdList = std::list < /* typename */ GroupNode<W, H>>;
}
}
// and then use NodeList<19, 19> nl;
Run Code Online (Sandbox Code Playgroud)
上面的代码可以在gcc-6和clang-3.9上编译而不会发出任何警告.然而,克利翁2016.3抱怨cannot resolve variable GroupNode在b.cpp.取消注释typename可以驯服Clion警告,但我想知道这是否typename是必需的?如果是这样,为什么g ++/clang ++没有发出任何警告?
在 C++ 中,依赖名称的概念很重要,因为:
这样的名称是未绑定的,并且在模板实例化的点上查找……在模板定义的上下文和实例化点的上下文中
但是,该标准唯一说的是在[temp.dep]/2 中给出了依赖名称,指的是不合格的函数调用,基本上是为了使 ADL 能够对那些函数调用完全有效。
除了这些外,还有其他依赖名称吗?
考虑一些这样的代码,例如:
template <class T>
void foo(T t) {
t.bar();
};
Run Code Online (Sandbox Code Playgroud)
如果有人将其bar称为“从属名称” ,根据标准,这是否在技术上不正确地使用该术语?
此代码在 Clang 和 Visual C++ 上可以正常编译,但在 GCC 上则不行:
#include <iostream>
template <class T>
struct Test {
Test(T &t) : _t(t) {
}
void method() {
std::cout << _t.Internal::_value << "\n"; // Doesn't work on GCC
std::cout << _t.T::Internal::_value << "\n"; // Work on all compilers
}
private:
T &_t;
};
template <class T>
struct Base {
T _value = 1;
};
template <class T>
struct Child : Base<int> {
using Internal = Base<int>;
int _value = 2;
};
int main(int …Run Code Online (Sandbox Code Playgroud) struct A{};
template <typename T>
struct B
{
typename ::A a1; //(1)
typename A a2; //(2): error
};
int main(){return 0;}
Run Code Online (Sandbox Code Playgroud)
为什么第一种情况是正确的,但第二种情况不正确?我不明白这种限制的含义.
无论如何,为什么第一个案例被允许?::A不是模板参数相关的名称.这有什么意义?
我们将一部分无法找到正确语法的代码减少到最小的示例.
我们假设以下定义(不用担心"为什么";)
template <class>
class Element
{};
template <template <class> class>
class Client
{};
template <class>
struct TemplatedProvider
{
template <class T>
using element_template = Element<T>;
};
Run Code Online (Sandbox Code Playgroud)
现在,在C++ 11之后,我们可以使用类模板或类型别名模板来实例化Client模板.以下函数编译得很好:
void fun()
{
Client<Provider::element_template> client;
Client<TemplatedProvider<int>::element_template> clientBis;
}
Run Code Online (Sandbox Code Playgroud)
但是,当给出的模板参数Client是依赖名称时,我们在以下情况下找不到正确的语法:
template <class T>
void templatedFun()
{
Client<TemplatedProvider<T>::element_template> client;
}
Run Code Online (Sandbox Code Playgroud)
Clang(用3.6测试)发出以下编译错误:
template argument for template template parameter must be a class template or type alias template
Run Code Online (Sandbox Code Playgroud)
我们可以修复这种语法吗?
在我的for循环中声明迭代器时研究无符号与有符号整数比较警告时,我读到了这个:
尽可能使用您要比较的确切类型(例如,
std::string::size_type与std::string长度比较时使用).
我QList<T>想要迭代,使用上面的方法声明迭代器:
for(QList::size_type i = 0; i < uploads.size(); i++)
{
//Do something
}
Run Code Online (Sandbox Code Playgroud)
它给了我一个编译器错误:
error: 'template<class T> class QList' used without template parameters
for(QList::size_type i = 0; i < uploads.size(); i++)
Run Code Online (Sandbox Code Playgroud)
为什么我不能以同样的方式使用它?这是由我还是由Qt框架及其类型引起的?QList::size_type在这种情况下,什么是一个很好的替代品,QList::size()只需返回一个常规的旧的int,我想使用它; 但我读了上面链接的帖子,这让我不确定.
考虑以下:
template<typename T> struct Foo {
typedef void NonDependent;
typedef typename T::Something Dependent;
}
Run Code Online (Sandbox Code Playgroud)
我想引用NonDependent而不指定任何模板参数,如Foo::NonDependent.
我知道我总是可以使用虚拟参数:
Foo<WhateverSuits>::NonDependent bla;
Run Code Online (Sandbox Code Playgroud)
但这很难看,而且由于它NonDependent是不变的T,我想在不依赖假人的情况下参考它.可能吗?
谢谢
我在以下代码中有一个编译错误.似乎编译器将类方法解释set为一个模板 - 乍一看 - 与我的代码完全无关.
#include <cassert>
#include <limits>
using namespace std;
template <class T>
class ReduceScalar{
public:
T get() { return *r; };
void set(T t) { *r = t; };
void set(T* t) { r = t; };
private:
T* r;
};
template <class T>
class ReduceSum : public ReduceScalar<T>
{
public:
ReduceSum(T* target) { set(target); set(0); } // COMPILE ERROR
};
Run Code Online (Sandbox Code Playgroud)
编译器给出以下错误:
../test/../io/scalarreducers.h:34:26: error: use of class template 'set' requires template arguments
ReduceSum(T* target) { …Run Code Online (Sandbox Code Playgroud) c++ ×11
dependent-name ×11
templates ×11
c++11 ×2
name-lookup ×2
inheritance ×1
qt ×1
typename ×1
visual-c++ ×1