这种情况会发生什么:
struct A {
void f();
};
struct B : virtual A {
using A::f;
};
struct C : virtual A {
using A::f;
};
struct D : B, C {
void g() {
f();
}
};
Run Code Online (Sandbox Code Playgroud)
感兴趣的是 f().显然,f根据10.2FDIS 的查找成功并找到A::f.但是,哪些候选人会考虑重载决议?规范说13.3.1p4:
对于由using声明引入到派生类中的非转换函数,该函数被认为是派生类的成员,用于定义隐式对象参数的类型.
这样做的目的是使单个类,如果这样一类同时包含自己的成员函数和using声明带来的基类函数的名称为范围,即重载解析过程中的所有功能,考生在他们的隐含对象是相同类型参数.但这对于上面的例子意味着什么呢?候选人是否会如下?
void F1(B&)
void F2(C&)
// call arguments: (lvalue D)
Run Code Online (Sandbox Code Playgroud)
这似乎是错误的,因为根据我们在查找结果集中只有一个声明10.2p7.我们该如何解读?
如果派生类定义了相同的名称,派生类将隐藏基类的重载名称,但我们总是可以使用using-declaration引入该重载集:
template <class BASE>
class A : public BASE
{
public:
using BASE::some_method;
void some_method();
}
Run Code Online (Sandbox Code Playgroud)
但是如果我从可变参数基类引入所有重载集呢?我可以写这样的东西吗?
template <class... BASES>
class A : public BASES...
{
public:
using BASES::some_method...;
void some_method();
}
Run Code Online (Sandbox Code Playgroud)
我考虑过使用一个帮助类:
template <class... BASES>
struct helper;
template <>
struct helper<> {};
template <class OnlyBase>
struct helper<OnlyBase> : OnlyBase
{
using OnlyBase::some_method;
};
template <class Base1, class... OtherBases>
struct helper<Base1, OtherBases> : public Base1, public helper<OtherBases...>
{
using Base1::some_method;
using helper<OtherBases...>::some_method;
};
Run Code Online (Sandbox Code Playgroud)
它确实有效.但它需要大量的输入(当然我可以使用宏,但我尽可能尝试使用c ++的编译时功能),当我想引入更多方法时,我必须在那段代码中做出很多改变.
一个完美的答案是一个简单的语法,但如果没有,我将使用帮助类.
c++ inheritance overloading using-declaration variadic-templates
请参考以下代码:
#include <algorithm>
namespace N
{
template <typename T>
class C
{
public:
void SwapWith(C & c)
{
using namespace std; // (1)
//using std::swap; // (2)
swap(a, c.a);
}
private:
int a;
};
template <typename T>
void swap(C<T> & c1, C<T> & c2)
{
c1.SwapWith(c2);
}
}
namespace std
{
template<typename T> void swap(N::C<T> & c1, N::C<T> & c2)
{
c1.SwapWith(c2);
}
}
Run Code Online (Sandbox Code Playgroud)
如上所述,代码无法在Visual Studio 2008/2010上编译.错误是:
'void N::swap(N::C<T> &,N::C<T> &)' : could not deduce template argument for 'N::C<T> &' …Run Code Online (Sandbox Code Playgroud) 在阅读这个问题时,我发现了一个奇怪的观点:
template <typename T>
class Subclass : public Baseclass<T>
{
public:
using typename Baseclass<T>::Baseclass;
// ^^^^^^^^
};
Run Code Online (Sandbox Code Playgroud)
既然typename,Baseclass<T>::Baseclass应该注入类名,而不是构造函数.据我所知,情况与此相同:
template <typename T>
class Base
{
public:
typedef short some_type;
};
template <typename T>
class Sub : public Base<T>
{
public:
using typename Base<T>::some_type;
};
Run Code Online (Sandbox Code Playgroud)
为了确保,我写了一个测试代码.
#include <iostream>
template <typename T>
class Base
{
public:
Base() { std::cout << "A::A()\n"; }
Base(int) { std::cout << "A::A(int)\n"; }
Base(const char *) { std::cout << "A::A(const …Run Code Online (Sandbox Code Playgroud) c++ typename using-declaration language-lawyer inheriting-constructors
以下程序与MSVS,clang和GCC编译时没有错误:
class A;
namespace Y {
using ::A;
class A {};
}
int main() {}
Run Code Online (Sandbox Code Playgroud)
现在让我们定义一个成员函数.现在它仍然可以编译MSVS和clang,但不能与GCC编译:
class A;
namespace Y {
using ::A;
class A { void f() {} };
}
int main() {}
Run Code Online (Sandbox Code Playgroud)
GCC给出以下错误消息:
这是为什么?这是GCC中的错误吗?
如果该程序的第二个版本违反了c ++标准的规则,它违反了什么规则,为什么MSVS和clang没有为该违规提供诊断消息?
这是c ++标准含糊不清的情况吗?
从错误消息看起来GCC错误地认为我们违反了以下规则:
我们没有违反此规则,因为成员函数定义在类定义中.我的理论是,海湾合作委员会混淆了宣言类A; 在全局命名空间中,在命名空间Y中有类定义类A {...}.我认为我们在GCC中有一个错误.
通过海湾合作委员会,他们宣布同一实体.通过观察在程序的第一个版本中可以看出,在使用GCC进行编译时,可以使用:: A作为main中的完整类型.MSVS也是如此.然而,对于Clang,他们宣布了不同的实体.这种差异可能是因为c ++标准的模糊性.无论这种模棱两可,我们显然都没有违反http://eel.is/c++draft/class.mfct#2.这个规则很清楚.
namespace A{
int i;
}
int main(){
using A::i;
using A::i;
}
Run Code Online (Sandbox Code Playgroud)
VS2010 - 编译好
gcc(ideone) - 编译好
Comeau - 给出错误""ComeauTest.c",第10行:错误:"i"已经在当前范围内使用A :: i声明;"
$ 7.3.3/8 - "使用声明是一种声明,因此可以在允许多个声明的情况下(并且仅在何处)重复使用."
这里的例子表明代码确实是不正确的.
那么,这是GCC和VS2010中的一个错误吗?
编辑2:
删除using directives与手头查询无关的倍数.
以下代码在g ++和clang中正确编译:
template<typename T>
struct foo
{
class iterator;
using bar = foo::iterator;
};
int main() {}
Run Code Online (Sandbox Code Playgroud)
但MSVC 2013会出现以下错误:
foo.cpp(9): error C2061: syntax error : identifier 'iterator'
foo.cpp(10) : see reference to class template instantiation 'foo<T>' being compiled
foo.cpp(9): error C2238: unexpected token(s) preceding ';'
Run Code Online (Sandbox Code Playgroud)
如果我将该行更改为:
using bar = typename foo::iterator;
Run Code Online (Sandbox Code Playgroud)
然后所有三个编译器都成功编译.原始版本是否正确?(即这是一个MSVC错误,还是一个gcc/clang扩展)
考虑这个例子:
struct B { operator int(); };
template<class T>
struct X:B
{
using B::operator T;
};
Run Code Online (Sandbox Code Playgroud)
请注意,如果基类型是相关的,则所有编译器都接受以下代码:
template<class T>
struct B { operator T(); };
template<class T>
struct X:B<T>
{
using B<T>::operator T;
};
Run Code Online (Sandbox Code Playgroud) 在下面的例子中,我试图通过在课堂上将其隐藏起来来隐藏using Employee::showEveryDept最后一个子Designer类Elayer-
#include <iostream>
class Employee {
private:
char name[5] = "abcd";
void allDept() { std::cout << "Woo"; }
public:
void tellName() { std::cout << name << "\n"; }
virtual void showEveryDept()
{
std::cout << "Employee can see every dept\n";
allDept();
}
};
class ELayer : public Employee {
private:
using Employee::showEveryDept;
protected:
ELayer() {}
public:
using Employee::tellName;
};
class Designer : public ELayer {
private:
char color = 'r';
public:
void showOwnDept() { …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接受使用声明,但似乎忽略它. …
c++ ×10
c++11 ×3
inheritance ×2
templates ×2
typename ×2
gcc ×1
namespaces ×1
overloading ×1
polymorphism ×1
swap ×1