C ++ 14 - C++14

C ++ 14 é uma versão do padrão ISO / IEC 14882 para a linguagem de programação C ++ . Pretende ser uma pequena extensão sobre o C ++ 11 , apresentando principalmente correções de bugs e pequenas melhorias. Sua aprovação foi anunciada em 18 de agosto de 2014. C ++ 14 foi publicado como ISO / IEC 14882: 2014 em dezembro de 2014.

Como as revisões do padrão C ++ anteriores estavam visivelmente atrasadas, o nome "C ++ 1y" às vezes era usado em seu lugar até sua aprovação, da mesma forma como o padrão C ++ 11 costumava ser denominado "C ++ 0x" com a expectativa de seu lançamento antes de 2010 (embora na verdade tenha entrado em 2010 e finalmente em 2011).

Novos recursos de linguagem

Esses são os recursos adicionados à linguagem central do C ++ 14.

Dedução de tipo de retorno de função

O C ++ 11 permitia que funções lambda deduzissem o tipo de retorno com base no tipo da expressão fornecida à instrução de retorno. C ++ 14 fornece essa capacidade para todas as funções. Ele também estende esses recursos para funções lambda, permitindo a dedução do tipo de retorno para funções que não são da forma return expression;.

Para induzir a dedução do tipo de retorno, a função deve ser declarada com autoo tipo de retorno, mas sem o especificador de tipo de retorno final em C ++ 11:

auto DeduceReturnType();   // Return type to be determined.

Se várias expressões de retorno forem usadas na implementação da função, todas devem deduzir o mesmo tipo.

As funções que deduzem seus tipos de retorno podem ser declaradas de forma direta, mas não podem ser usadas até que tenham sido definidas. Suas definições devem estar disponíveis para a unidade de tradução que as utiliza.

A recursão pode ser usada com uma função deste tipo, mas a chamada recursiva deve acontecer após pelo menos uma instrução de retorno na definição da função:

auto Correct(int i)
{
  if (i == 1)
    return i;             // return type deduced as int

  return Correct(i-1)+i;  // ok to call it now
}

auto Wrong(int i)
{
  if (i != 1)
    return Wrong(i-1)+i;  // Too soon to call this. No prior return statement.

  return i;               // return type deduced as int
}

Dedução de tipo alternativo na declaração

No C ++ 11, dois métodos de dedução de tipo foram adicionados. autoera uma maneira de criar uma variável do tipo apropriado, com base em uma determinada expressão. decltypeera uma forma de calcular o tipo de uma determinada expressão. No entanto, decltypee autodeduzir tipos de maneiras diferentes. Em particular, autosempre deduz um tipo de não referência, como se estivesse usando std::decay, enquanto auto&&sempre deduz um tipo de referência. No entanto, decltypepode ser estimulado a deduzir um tipo de referência ou não-referência, com base na categoria de valor da expressão e na natureza da expressão que está deduzindo:

int   i;
int&& f();
auto          x3a = i;     // decltype(x3a) is int
decltype(i)   x3d = i;     // decltype(x3d) is int
auto          x4a = (i);   // decltype(x4a) is int
decltype((i)) x4d = (i);   // decltype(x4d) is int&
auto          x5a = f();   // decltype(x5a) is int
decltype(f()) x5d = f();   // decltype(x5d) is int&&

C ++ 14 adiciona a decltype(auto)sintaxe. Isso permite que as autodeclarações usem as decltyperegras da expressão fornecida.

A decltype(auto)sintaxe também pode ser usada com a dedução do tipo de retorno , usando a decltype(auto)sintaxe em vez de autopara a dedução do tipo de retorno da função.

Restrições de constexpr relaxadas

C ++ 11 introduziu o conceito de uma função declarada constexpr; uma função que pode ser executada em tempo de compilação. Seus valores de retorno podem ser consumidos por operações que requerem expressões constantes, como um argumento de modelo inteiro. No entanto, as funções constexpr do C ++ 11 podem conter apenas uma única expressão que é retornada (bem como static_asserts e um pequeno número de outras declarações).

C ++ 14 relaxa essas restrições. As funções declaradas por Constexpr agora podem conter o seguinte:

  • Quaisquer declarações, exceto:
    • staticou thread_localvariáveis.
    • Declarações de variáveis ​​sem inicializadores.
  • As instruções de ramificação condicional ife switch.
  • Qualquer instrução de loop, incluindo baseada em intervalo for.
  • Expressões que alteram o valor de um objeto se o tempo de vida desse objeto começou dentro da função de expressão constante. Isso inclui chamadas para quaisquer const constexprfunções de membro não estáticas não declaradas.

goto instruções são proibidas em funções declaradas constexpr relaxadas do C ++ 14.

Além disso, o C ++ 11 afirmou que todas as funções de membro não estáticas que foram declaradas constexprtambém foram declaradas implicitamente const, em relação a this. Isso já foi removido; funções de membro não estáticas podem ser não const. No entanto, de acordo com as restrições acima, uma const constexprfunção não membro só pode modificar um membro da classe se o tempo de vida desse objeto começar na avaliação da expressão constante.

Modelos de variáveis

Em versões anteriores de C ++ , apenas funções, classes ou apelidos de tipo podiam ser modelados. C ++ 14 permite a criação de variáveis ​​que são modeladas. Um exemplo dado na proposta é uma variável pique pode ser lida para obter o valor de pi para vários tipos (por exemplo, 3quando lida como um tipo integral; o valor mais próximo possível com float, doubleou long doubleprecisão quando lida como float, doubleou long double, respectivamente; etc. )

As regras usuais de modelos se aplicam a tais declarações e definições, incluindo especialização.

template<typename T>
constexpr T pi = T(3.141592653589793238462643383);

// Usual specialization rules apply:
template<>
constexpr const char* pi<const char*> = "pi";

Inicialização de membro agregado

C ++ 11 adicionou inicializadores de membro, expressões a serem aplicadas aos membros no escopo da classe se um construtor não inicializou o próprio membro. A definição de agregados foi alterada para excluir explicitamente qualquer classe com inicializadores de membro; portanto, eles não têm permissão para usar a inicialização agregada.

C ++ 14 relaxa essa restrição, permitindo a inicialização de agregação em tais tipos. Se a lista de inicialização entre chaves não fornecer um valor para esse argumento, o inicializador de membro cuidará disso.

Literais binários

Literais numéricos em C ++ 14 podem ser especificados na forma binária . A sintaxe usa os prefixos 0bou 0B. A sintaxe também é usada em outras linguagens, por exemplo , Java , C # , Swift , Go , Scala , Ruby , Python , OCaml e como uma extensão não oficial em alguns compiladores C desde pelo menos 2007.

Separadores de dígitos

Em C ++ 14, o caractere de aspas simples pode ser usado arbitrariamente como um separador de dígitos em literais numéricos, literais inteiros e literais de ponto flutuante. Isso pode tornar mais fácil para os leitores humanos analisar grandes números por meio da legendagem .

auto integer_literal = 1'000'000;
auto floating_point_literal = 0.000'015'3;
auto binary_literal = 0b0100'1100'0110;
auto a_dozen_crores = 12'00'00'000;

Lambdas genéricas

No C ++ 11, os parâmetros da função lambda precisam ser declarados com tipos concretos. C ++ 14 relaxa esse requisito, permitindo que os parâmetros da função lambda sejam declarados com o autoespecificador de tipo.

auto lambda = [](auto x, auto y) {return x + y;};

Com relação à autodedução de tipo, lambdas genéricos seguem as regras de dedução de argumento de modelo (que são semelhantes, mas não idênticas em todos os aspectos). O código acima é equivalente a este:

struct
{
  template<typename T, typename U>
    auto operator()(T x, U y) const {return x + y;}
} lambda{};

Lambdas genéricos são essencialmente lambdas de functor modelado.

Expressões de captura lambda

As funções lambda do C ++ 11 capturam variáveis ​​declaradas em seu escopo externo por cópia de valor ou por referência. Isso significa que os membros de valor de um lambda não podem ser tipos apenas de movimentação. C ++ 14 permite que membros capturados sejam inicializados com expressões arbitrárias. Isso permite a captura por movimento de valor e a declaração de membros arbitrários do lambda, sem ter uma variável com o nome correspondente em um escopo externo.

Isso é feito por meio do uso de uma expressão inicializadora:

auto lambda = [value = 1] {return value;};

A função lambda lambdaretorna 1, que é o que valuefoi inicializado. A captura declarada deduz o tipo da expressão do inicializador como se por auto.

Isso pode ser usado para capturar por movimento, por meio do uso da std::movefunção padrão :

std::unique_ptr<int> ptr(new int(10));
auto lambda = [value = std::move(ptr)] {return *value;};

O atributo [[deprecated]]

O deprecatedatributo permite marcar uma entidade como obsoleta , o que torna seu uso ainda legal, mas avisa os usuários de que o uso é desencorajado e pode fazer com que uma mensagem de aviso seja impressa durante a compilação. Um literal de string opcional pode aparecer como o argumento de deprecated, para explicar o motivo da reprovação e sugerir uma substituição.

[[deprecated]] int f();

[[deprecated("g() is thread-unsafe. Use h() instead")]]
void g( int& x );

void h( int& x );

void test()
{
  int a = f(); // warning: 'f' is deprecated
  g(a); // warning: 'g' is deprecated: g() is thread-unsafe. Use h() instead
}

Novos recursos de biblioteca padrão

Mutexes compartilhados e bloqueio

C ++ 14 adiciona um mutex temporizado compartilhado e um tipo de bloqueio compartilhado complementar.

Pesquisa heterogênea em contêineres associativos

A C ++ Standard Library define quatro classes de contêiner associativo. Essas classes permitem que o usuário pesquise um valor com base em um valor desse tipo. Os contêineres de mapa permitem que o usuário especifique uma chave e um valor, onde a pesquisa é feita por chave e retorna um valor. No entanto, a pesquisa é sempre feita pelo tipo de chave específico, seja a chave como nos mapas ou o próprio valor como nos conjuntos.

C ++ 14 permite que a pesquisa seja feita por meio de um tipo arbitrário, desde que o operador de comparação possa comparar esse tipo com o tipo de chave real. Isso permitiria um mapa de std::stringpara algum valor para comparar com um const char*ou qualquer outro tipo para o qual uma operator< sobrecarga esteja disponível. Também é útil para indexar objetos compostos em a std::setpelo valor de um único membro sem forçar o usuário de finda criar um objeto fictício (por exemplo, criar um inteiro struct Personpara localizar uma pessoa pelo nome).

Para preservar a compatibilidade com versões anteriores, a pesquisa heterogênea só é permitida quando o comparador fornecido ao contêiner associativo permite. As classes da biblioteca padrão std::less<>e std::greater<>são aumentadas para permitir pesquisa heterogênea.

Literais padrão definidos pelo usuário

C ++ 11 definiu a sintaxe para sufixos literais definidos pelo usuário, mas a biblioteca padrão não usou nenhum deles. C ++ 14 adiciona os seguintes literais padrão:

  • "s", para criar os vários std::basic_stringtipos.
  • "h", "min", "s", "ms", "us", "ns", para criar os std::chrono::durationintervalos de tempo correspondentes .
  • "se", "i", "il", para criar as correspondentes std::complex<float>, std::complex<double>e std::complex<long double>os números imaginários.
auto str = "hello world"s; // auto deduces string
auto dur = 60s;            // auto deduces chrono::seconds
auto z   = 1i;             // auto deduces complex<double>

Os dois literais "s" não interagem, pois a string um opera apenas em literais de string e a de segundos opera apenas em números.

Endereçamento de tupla via tipo

O std::tupletipo introduzido no C ++ 11 permite que um agregado de valores digitados seja indexado por um número inteiro constante de tempo de compilação. C ++ 14 estende isso para permitir a busca de uma tupla por tipo em vez de por índice. Se a tupla tiver mais de um elemento do tipo, ocorrerá um erro em tempo de compilação:

tuple<string, string, int> t("foo", "bar", 7);
int i = get<int>(t);        // i == 7
int j = get<2>(t);          // Same as before: j == 7
string s = get<string>(t);  // Compile-time error due to ambiguity

Recursos de biblioteca menores

std::make_uniquepode ser usado como std::make_sharedpara std::unique_ptrobjetos.

std::integral_constantganhou uma operator()sobrecarga para retornar o valor constante.

O modelo de classe std::integer_sequencee os modelos de alias relacionados foram adicionados para representar sequências inteiras em tempo de compilação, como os índices de elementos em um pacote de parâmetros.

As funções globais std::begin/ std::endforam aumentadas com funções std::cbegin/ std::cend, que retornam iteradores constantes e std::rbegin/ std::rende std::crbegin/ std::crendque retornam iteradores reversos.

O std::exchangemodelo de função atribui um novo valor a uma variável e retorna o valor antigo.

Novas sobrecargas de std::equal, std::mismatche std::is_permutationusam um par de iteradores para o segundo intervalo, de modo que o chamador não precise verificar separadamente se os dois intervalos têm o mesmo comprimento.

O std::is_finaltraço de tipo detecta se uma classe está marcada final.

O std::quotedmanipulador de fluxo de I / O permite a inserção e extracção de cordas com espaços incorporados, colocando delimitadores (em falta para aspas) na saída e retirando-os na entrada, e escapar quaisquer delimitadores incorporados.

Suporte a compilador

O Clang finalizou o suporte para C ++ 14 em 3.4 embora com o nome padrão c ++ 1y, e tornou C ++ 14 o padrão C ++ padrão no Clang 6. O GCC finalizou o suporte para C ++ 14 no GCC 5 e tornou-se C + +14 o padrão C ++ padrão no GCC 6. O Microsoft Visual Studio 2017 implementou "quase todos" os recursos do C ++ 14.

Referências

links externos