That's where the C++14 feature comes in

  • 2020-10-31 21:53:53
  • OfStack

The previous program meow introduced the new features of C++11, here (), this article introduces the new features of C++14.

Function return value type derivation

C++14 has optimized the derivation rules of function return type. First, take a look at 1 section of code:


#include <iostream>

using namespace std;

auto func(int i) {
  return i;
}

int main() {
  cout << func(4) << endl;
  return 0;
}

Compile with C++11:


~/test$ g++ test.cc -std=c++11
test.cc:5:16: error:  ' func' function uses  ' auto' type specifier without trailing return type
 auto func(int i) {
        ^
test.cc:5:16: note: deduced return type only available with -std=c++14 or -std=gnu++14

The above code is not compiled using C++11, and you can see from the compiler output that this feature is not supported until C++14.

Return value type derivation can also be used in templates:


#include <iostream>
using namespace std;

template<typename T> auto func(T t) { return t; }

int main() {
  cout << func(4) << endl;
  cout << func(3.4) << endl;
  return 0;
}

Note:

If there are multiple return statements within the function, they must return the same type, or the compilation fails.


auto func(bool flag) {
  if (flag) return 1;
  else return 2.3; // error
}
// inconsistent deduction for auto return type:  ' int' and then  ' double'

If the return statement returns the initialization list, the return value type derivation also fails


auto func() {
  return {1, 2, 3}; // error returning initializer list
}

If the function is a virtual function, you cannot derive it using a return value type


struct A {
  // error: virtual function cannot have deduced return type
  virtual auto func() { return 1; } 
}

Return type derivations can be used in forward declarations, but before they can be used, function definitions must be available in the translation unit


auto f();        // declared, not yet defined
auto f() { return 42; } // defined, return type is int

int main() {
  cout << f() << endl;
}

Return type derivation can be used in recursive functions, but recursive calls must be preceded by at least one return statement for the compiler to derive the return type.


auto sum(int i) {
  if (i == 1)
    return i;       // return int
  else
    return sum(i - 1) + i; // ok
}

auto lambda parameters

In C++11, the lambda expression parameter needs to be declared with a specific type:


auto f = [] (int a) { return a; }

In C++14, the parameter of lambda expression can be directly auto:


auto f = [] (auto a) { return a; };
cout << f(1) << endl;
cout << f(2.3f) << endl;

Variable template

C++14 supports variable template:


~/test$ g++ test.cc -std=c++11
test.cc:5:16: error:  ' func' function uses  ' auto' type specifier without trailing return type
 auto func(int i) {
        ^
test.cc:5:16: note: deduced return type only available with -std=c++14 or -std=gnu++14
0

The alias template

C++14 also supports alias templates:


template<typename T, typename U>
struct A {
  T t;
  U u;
};

template<typename T>
using B = A<T, int>;

int main() {
  B<double> b;
  b.t = 10;
  b.u = 20;
  cout << b.t << endl;
  cout << b.u << endl;
  return 0;
}

The limitation of constexpr

Compared with C++14, C++ 11 reduces constexpr by 1:

The constexpr function can use recursion in C++11, and local variables and loops can be used in C++14


constexpr int factorial(int n) { // C++14  and  C++11 All can 
  return n <= 1 ? 1 : (n * factorial(n - 1));
}

You can do this in C++14:


~/test$ g++ test.cc -std=c++11
test.cc:5:16: error:  ' func' function uses  ' auto' type specifier without trailing return type
 auto func(int i) {
        ^
test.cc:5:16: note: deduced return type only available with -std=c++14 or -std=gnu++14
3

The constexpr function in C++11 must put everything in a single return statement, whereas constexpr has no such restriction:


~/test$ g++ test.cc -std=c++11
test.cc:5:16: error:  ' func' function uses  ' auto' type specifier without trailing return type
 auto func(int i) {
        ^
test.cc:5:16: note: deduced return type only available with -std=c++14 or -std=gnu++14
4

In C++14 you can do this:


~/test$ g++ test.cc -std=c++11
test.cc:5:16: error:  ' func' function uses  ' auto' type specifier without trailing return type
 auto func(int i) {
        ^
test.cc:5:16: note: deduced return type only available with -std=c++14 or -std=gnu++14
5

[[deprecated]]

C++14 added deprecated tags, modifier classes, variables, functions, etc. When the modified code is used in the program, a warning will be generated at compile time, and users will prompt the developer that the modified content may be discarded in the future, so try not to use it.


~/test$ g++ test.cc -std=c++11
test.cc:5:16: error:  ' func' function uses  ' auto' type specifier without trailing return type
 auto func(int i) {
        ^
test.cc:5:16: note: deduced return type only available with -std=c++14 or -std=gnu++14
6

When compiled, the following warning appears:


~/test$ g++ test.cc -std=c++14
test.cc: In function  ' int main()':
test.cc:11:7: warning:  ' A' is deprecated [-Wdeprecated-declarations]
   A a;
    ^
test.cc:6:23: note: declared here
 struct [[deprecated]] A {

Separator between base 2 literals and plastic literals

C++14 introduced base 2 literals as well as delimiters to prevent it from looking dazzling


int a = 0b0001'0011'1010;
double b = 3.14'1234'1234'1234;

std::make_unique

We all know that C++11 has std::make_shared, but not std::make_unique, which has been improved in C++14.


~/test$ g++ test.cc -std=c++11
test.cc:5:16: error:  ' func' function uses  ' auto' type specifier without trailing return type
 auto func(int i) {
        ^
test.cc:5:16: note: deduced return type only available with -std=c++14 or -std=gnu++14
9

std: : shared_timed_mutex and std: : shared_lock

C++14 realizes the read-write lock through std::shared_timed_mutex and std::shared_lock to ensure that multiple threads can read at the same time, but the write thread must run independently, and the write operation cannot be carried out simultaneously with the read operation 1.

The implementation is as follows:


struct ThreadSafe {
  mutable std::shared_timed_mutex mutex_;
  int value_;

  ThreadSafe() {
    value_ = 0;
  }

  int get() const {
    std::shared_lock<std::shared_timed_mutex> loc(mutex_);
    return value_;
  }

  void increase() {
    std::unique_lock<std::shared_timed_mutex> lock(mutex_);
    value_ += 1;
  }
};

Why is timed's lock? Because it can take timeout, specific you can query the relevant information ha, there are many on the Internet.

std::integer_sequence


template<typename T, T... ints>
void print_sequence(std::integer_sequence<T, ints...> int_seq)
{
  std::cout << "The sequence of size " << int_seq.size() << ": ";
  ((std::cout << ints << ' '), ...);
  std::cout << '\n';
}

int main() {
  print_sequence(std::integer_sequence<int, 9, 2, 5, 1, 9, 1, 6>{});
  return 0;
}

Output: 7, 9, 2, 5, 1, 9, 1, 6

std::integer_sequence and std::tuple


template <std::size_t... Is, typename F, typename T>
auto map_filter_tuple(F f, T& t) {
  return std::make_tuple(f(std::get<Is>(t))...);
}

template <std::size_t... Is, typename F, typename T>
auto map_filter_tuple(std::index_sequence<Is...>, F f, T& t) {
  return std::make_tuple(f(std::get<Is>(t))...);
}

template <typename S, typename F, typename T>
auto map_filter_tuple(F&& f, T& t) {
  return map_filter_tuple(S{}, std::forward<F>(f), t);
}

std::exchange

Look directly at the code:


int main() {
  std::vector<int> v;
  std::exchange(v, {1,2,3,4});
  cout << v.size() << endl;
  for (int a : v) {
    cout << a << " ";
  }
  return 0;
}

It looks like std::swap does the same thing, so what's the difference?

Take a look at the implementation of exchange:


template<class T, class U = T>
constexpr T exchange(T& obj, U&& new_value) {
  T old_value = std::move(obj);
  obj = std::forward<U>(new_value);
  return old_value;
}

You can see that new_value was assigned to obj and no new_value was assigned to value, so I'm sure you already know the difference!

std::quoted

C++14 std::quoted is used to add double quotation marks to a string.


int main() {
  string str = "hello world";
  cout << str << endl;
  cout << std::quoted(str) << endl;
  return 0;
}

compile & Output:


~/test$ g++ test.cc -std=c++14
~/test$ ./a.out
hello world
"hello world"

About C++14, we have introduced these new features. The next issue is C++17. Please stay tuned! Welcome star in watch point like and forward ~

Refer to the link

https://en.cppreference.com/w/cpp/14

https://en.cppreference.com/w/cpp/language/function#Return_type_deduction_.28since_C.2B.2B14.29

https://en.cppreference.com/w/cpp/language/lambda

https://en.cppreference.com/w/cpp/language/constexpr

https://en.cppreference.com/w/cpp/language/constexpr


Related articles: