Qual é a lógica por trás da palavra-chave "usar" em C++?
Qual é a lógica por trás da palavra-chave "usar" em C++?
É usado em situações diferentes e estou a tentar encontrar se todos eles têm algo em comum e há uma razão por que a palavra-chave "usando" é usada como tal.using namespace std; // to import namespace in the current namespace
using T = int; // type alias
using SuperClass::X; // using super class methods in derived class
1 answers
Em C++11, a palavra-chave using
quando usada para type alias
é idêntica a typedef
.
7.1.3.2
Um nome dactilografado também pode ser introduzido por uma declaração alias. O o identificador que segue a palavra-chave usada torna-se um nome tipadoef e o atributo-specificer-seq opcional seguindo o identificador aparece a esse nome escrito. Tem a mesma semântica como se fosse introduzido pelo especificador typedef. Em especial, não define um novo tipo e TI não deve figurar na identificação do tipo.
Bjarne Stroustrup dá um exemplo prático:
typedef void (*PFD)(double); // C style
using PF = void (*)(double); // using plus C-style type
using P = [](double)->void; // using plus suffix return type, syntax error
using P = auto(double)->void // Fixed thanks to DyP
Pré-C++11, a palavra-chave using
pode tornar as funções dos membros abrangidas pelo âmbito de Aplicação. Em C++11, Você pode agora fazer isso para construtores (outro exemplo de Bjarne Stroustrup):
class Derived : public Base {
public:
using Base::f; // lift Base's f into Derived's scope -- works in C++98
void f(char); // provide a new f
void f(int); // prefer this f to Base::f(int)
using Base::Base; // lift Base constructors Derived's scope -- C++11 only
Derived(char); // provide a new constructor
Derived(int); // prefer this constructor to Base::Base(int)
// ...
};
Ben Voight fornece uma boa razão por trás da lógica de não introduzir uma nova palavra-chave ou uma nova sintaxe. O padrão quer evitar quebrar o código antigo tanto quanto possível. É por isso que em documentos das propostas Impact on the Standard
, Design decisions
, e como podem afectar o código antigo. Há situações em que uma proposta parece ser realmente uma boa ideia, mas pode não ter força porque seria demasiado difícil de implementar, demasiado confuso, ou iria contradizer o antigo código.
Aqui está um artigo antigo de 2003 n1449. A lógica parece estar relacionada com modelos. Atenção: pode haver erros devido à cópia do PDF.
Primeiro vamos considere um exemplo do brinquedo:O problema fundamental deste idioma e o principal facto motivador para esta proposta, é que o idioma faz com que os parâmetros do modelo para aparece num contexto não dedutível. Ou seja, não será possível invocar a função foo abaixo sem especificar explicitamente o modelo argumento.template <typename T> class MyAlloc {/*...*/}; template <typename T, class A> class MyVector {/*...*/}; template <typename T> struct Vec { typedef MyVector<T, MyAlloc<T> > type; }; Vec<int>::type p; // sample usage
Então, a sintaxe é um pouco feia. Preferimos evitar o ninho. Preferíamos algo como o seguinte:template <typename T> void foo (Vec<T>::type&);
template <typename T> using Vec = MyVector<T, MyAlloc<T> >; //defined in section 2 below Vec<int> p; // sample usage
Note que nós especificamente evitamos o termo "modelo typedef" e intr reduzir a nova sintaxe envolvendo o par "usando" e " = " para ajudar a evitar confusão: não estamos aqui a definir nenhum tipo, estamos a introduzir um sinónimo (ou seja, também conhecido) de uma abstracção de um tipo de ID (Ou seja, tipo expressão) envolvendo parâmetros do modelo. Se os parâmetros do modelo são usados em contextos dedutíveis na expressão do tipo em seguida, sempre que o nome alternativo do modelo é usado para formar um ID-modelo, os valores de o os parâmetros correspondentes do modelo podem ser deduzidos-mais sobre este irá seguir. Em qualquer caso, agora é possível escrever funções genéricas que operam em
Vec<T>
num contexto dedutível, e a sintaxe é melhorou também. Por exemplo, poderíamos reescrever foo como:Sublinhamos aqui que uma das principais razões para propor os nomes alternativos do modelo foram de modo que a dedução de argumentos e a chamada paratemplate <typename T> void foo (Vec<T>&);
foo(p)
vai ter sucesso.
O documento de acompanhamento n1489 explica porque using
Em vez de usar typedef
:
Foi sugerido (re)usar a palavra-chave digitada-como feito na papel [4] - introduzir nomes alternativos de modelo:
template<class T> typedef std::vector<T, MyAllocator<T> > Vec;
Essa notação tem a vantagem de usar uma palavra-chave já conhecida por introduza um nome falso. No entanto, ele também exibe vários desacordos entre os quais a confusão de usar uma palavra-chave conhecida por introduzir uma alcunha para um nome de tipo num contexto em que a alcunha o faz nao designar um tipo, mas um modelo;
Vec
não é um nome alternativo para um digite, e não deve ser tomado para um nome tipadoef. O nomeVec
é a nome da famíliastd::vector< [bullet] , MyAllocator< [bullet] > >
- onde a bala é um substituto para um nome-tipo. Por conseguinte, não proponha a sintaxe "typedef". Por outro lado, a frasetemplate<class T> using Vec = std::vector<T, MyAllocator<T> >;
Pode ser lido / interpretado como: a partir de Agora, vou usar
Vec<T>
como um sinónimo destd::vector<T, MyAllocator<T> >
. Com essa leitura, o a nova sintaxe para o aliasing parece razoável logico.
Penso que é feita aqui a distinção importante, também conhecido por es em vez de Tipo s. outra citação do mesmo documento:
Uma alias-declaração é uma declaração, e não uma definição. Pseudonimo- declaração introduz um nome numa região declarativa como pseudónimo para o tipo designado pelo lado direito da declaração. O o núcleo desta proposta diz respeito a si próprio com nomes falsos, mas o a notação pode obviamente generalizar-se para fornecer ortografias alternativas do conjunto de nomes-aliasing ou de nomes das funções sobrecarregadas (ver ✁ 2.3 para discussão). [[[86]} minha nota: essa seção discute como essa sintaxe pode se parecer e as razões pelas quais ela não faz parte da proposta.[[[87]}] note-se que a gramática produção alias-declaração é aceitável em qualquer lugar um tipedef declaração ou uma definição de namespace-alias-é aceitável.
Resumo, para o papel do using
:
- nomes alternativos de modelos (ou modelos tipados, o primeiro é preferido no sentido dos nomes)
- nomes alternativos (ou seja,
namespace PO = boost::program_options
eusing PO = ...
equivalentes)
O documento diz: É uma mudança estética, e é considerada idêntica neste caso.
- colocar algo no âmbito (por exemplo,
namespace std
no âmbito global), funções dos membros, herdar Construtores
Não pode ser usado para:
int i;
using r = i; // compile-error
Em vez disso do:
using r = decltype(i);
Nomeando um conjunto de cargas excessivas.
// bring cos into scope
using std::cos;
// invalid syntax
using std::cos(double);
// not allowed, instead use Bjarne Stroustrup function pointer alias example
using test = std::cos(double);