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
 72
Author: user3111311, 2013-12-27

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:
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
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> void foo (Vec<T>::type&);
Então, a sintaxe é um pouco feia. Preferimos evitar o ninho. Preferíamos algo como o seguinte:
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:

template <typename T> void foo (Vec<T>&);
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 para 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 nome Vec é a nome da família std::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 frase

template<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 de std::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 e using 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);
 66
Author: , 2013-12-26 22:28:42