Accelerated c+++ function

function

actual combat

#include <iostream>
int myAdd(int,int);
int main()
{
    int x=10;
    int y=20;
    std::cout<<x<<"+"<<y<<"="<<myAdd(x,y)<<std::endl;
    return 0;
}
int myAdd(int x,int y) 
{
    return x+y;
}

Main points

1. Function calls

2. Functional parameters

3. Function return

lambda anonymous function

actual combat

#include <iostream>

auto myAdd= [](int x, int y) { return x+y;};// Implicit return type
int main()
{
    int x1=10;
    int x2=20;
    std::cout<<x1<<"+"<<x2<<"="<<myAdd(x1,x2)<<std::endl;
    return 0;
}

Main points

1.auto can automatically select a matching type for a variable according to the type of its initial value when declaring it.

2. The command of the compiler (i.e. adding the compilation option - std=c++11, which means using the c++11 standard, because this example complies with the c++11 standard, such as: auto, anonymous function myAdd):
g++ "/Users/deepmyhaspl/docs/teacher/c++/learn-1/1-3/main.cpp" -std=c++11 -o ./myprogram -I. -I.
Or check directly in CodeLite

[External Link Picture Transfer Failure (img-Vy9mrBx7-1568294615375)(/Users/deepmyhaspl/docs/teacher/c++/1_1.png)]

  1. The Lambda expression is as follows:

capture->return-type{body}

myAdd can also be defined as follows

[](int x, int y) -> int { int z = x + y; return z; }
[]        //No variables are defined. It is wrong to attempt to use any external variables in Lambda.
[x, &y]   //x is captured by value and y by reference.
[&]       //Any external variables used are implicitly captured by reference
[=]       //Any external variables used are implicitly captured by value
[&, x]    //x is explicitly captured by value. Other variables are captured by reference
[=, &z]   //z is captured by reference. Other variables are captured by value

Capture represents capture variables

#include <iostream>
int main()
{
    int x1=10;
    int x2=20;
    auto mySwap=[&x1,&x2]() { auto temp=x1;x1=x2;x2=temp;};
    mySwap();
    std::cout<<x1<<std::endl;
    std::cout<<x2<<std::endl;
    return 0;
}
#include <iostream>
int main()
{
    int x1=10;
    int x2=20;
    auto mySwapAdd=[&x1,&x2](int y) { auto temp=x1;x1=x2;x2=temp;x1+=y;x2+=y;};
    mySwapAdd(5);
    std::cout<<x1<<std::endl;
    std::cout<<x2<<std::endl;
    return 0;
}
#include <iostream>
//Compiled using the C++14 standard, because myAdd, a function variable (as a function object), is a variable template.
template<typename T>
auto myAdd=[](T x,T y) { return x+y;};
int main()
{
    int x1=10;
    int x2=20;
    std::cout<<myAdd<int>(x1,x2)<<std::endl;
    return 0;
}
#include <iostream>
template<typename T>
T var;//Variable template
int main()
{
    var<int> =10;
    var<double> =20.364;
    std::cout<< var<int> <<"  "<< var<double> <<std::endl;
    return 0;
}

constexpr function

c++11 standard

If a function may be evaluated at compile time, it is declared constexpr to improve efficiency. You need to use constexpr to tell the compiler to allow compile-time calculations.

constexpr does not guarantee a certain amount of computation at compile time. If necessary, constant expression parameters can be evaluated at compile time.

constexpr int min(int x, int y) { return x < y ? x : y; }
void test(int v)
{
    int m1 = min(-1, 2);            // Maybe at compile time
    constexpr int m2 = min(-1, 2);  // Compile-time computation
    int m3 = min(-1, v);            // Runtime Computing
    constexpr int m4 = min(-1, v);  // Error, cannot be calculated at compile time
}

Don't try to make all functions constant. Most calculations are best done at runtime.

Any API that may ultimately rely on advanced runtime or business logic should not be constexpr. The compiler cannot compute this customization, and any constexpr functions that depend on the API must be reconstructed or deleted.

int dcount = 0;
constexpr int double(int v)
{
    ++dcount;   // The constexpr function has no side effects because of this line error
    return v + v;
}
constexpr int factorial (int n)
{
    return n > 0 ? n * factorial( n - 1 ) : 1;
}

Inline

Main points

Inline functions are usually short programs. The member functions defined in the class are inlined by default. Inline is a modification of inline functions. Inline improves the speed of calling simple functions. Inline can not be recursive, the following procedure is wrong!

inline int factorial (int n)
{
return n > 0 ? n * factorial( n - 1 ) : 1;//error!
}
  • The constexpr function is implicitly specified as an inline function.
  • constexpr allows recursion.
#include <iostream>
constexpr int fac(int n)
{
    return n > 0 ? n * fac( n - 1 ) : 1;
}
inline int myadd(int x,int y){return x+y;};
int main()
{
    int n;
    std::cout<<"Please enter factorial parameters:";
    std::cin>>n;
    std::cout<<std::endl<<fac(n)<<std::endl;
    std::cout<<myadd(12,55)<<std::endl;
    return 0;
}

Optional Attribute List (C++11)

Optional attribute List. These attributes apply to the function type, not to the function itself. Attributes appearing after identifiers in the declarer are merged with those appearing at the beginning of the declaration if they exist.

1) Simple attributes, such as [[noreturn]]
2) Attributes with namespaces, such as [[gnu::unused]]
3) Attributes with parameters, such as [[deprecated("because")]]
4) Attributes, with namespaces and parameter lists

Attributes provide a unified standard grammar for the implementation of defined language extensions, such as GNU and IBM language extensions _attribute_(... ) Microsoft extensions _declspec(), etc.

In c++ programs, an attribute can be used almost anywhere, and can be applied to almost all types, variables, functions, names, code blocks, the entire transformation unit, although each specific attribute is only allowed to be implemented effectively: [[expect_true]] can be an attribute, only if, not a class declaration. [[omp::parallel()]] can be attributes applied to code blocks or for loops, but not to int types, etc.

In a declaration, attributes can appear before the entire declaration or directly after the name of the declared entity. In this case, attributes are grouped together. In most other cases, attributes apply to previous entities.

The alignas descriptor is part of the sequence of attribute descriptors, although it has different syntax. It may appear in [[... ]] Where attributes appear and may be mixed with them (if alignas is allowed)

Two consecutive left bracket tokens ([[]) can only occur when attribute descriptors or attribute parameters are introduced.

Attributes that appear before a declaration and immediately after an identifier in a declarer apply to the same entity declared or defined

  1. [[noreturn]] and [[deprecated("reason")]:

(1) [[noreturn]] indicates that the function never returns (the specified function does not return because it executes the return statement or arrives at the end of the function body, and can jump to the specified position by executing longjmp(c++17).) This helps the compiler to compile and optimize (e.g., tail recursion), and can also be used to suppress the compiler from giving unnecessary warnings. Sue.

Attributes can appear before the entire declaration, or directly after the entity name of the declaration, while attributes that appear after the declarer (grammatically) apply to the function type, not to the function itself.

Load the execution environment env saved by the previous setjmp call. This function does not return. Control is transferred to the call point of the macro setjmp with env set. The setjmp then returns the value passed as status.

(2)[[deprecated("reason")]]

[[deprecated(string-literal)]]

Indicates that a name or entity declaring this property is allowed, but is not encouraged for some reason. Compilers often issue warnings in this use. If string-literal is specified, it is usually included in the warning.

# include <iostream>
#include <csetjmp>
using namespace std;
jmp_buf jump_buffer;//std namespace, < csetjmp >

[[noreturn]]void addNum2[[noreturn]](int &res,int a){
    res+=a;
    cout<<"addnum:"<<a<<"="<<res<<endl;
    longjmp(jump_buffer,a+1);  // setjump() returns a+1
    
}

void addNum1(int a ,int b,int &res){//Note that res is a reference, that is, an alias for a variable, which is equivalent to passing a pointer rather than a value.
    res= a+b;
}

[[deprecated("dfunc has been deprecated ")]]void dfunc(){
    cout<<"dfunc"<<endl;
}
 

int main(int argc, char **argv)
{
	int x=0;
    int y[[deprecated("y has been deprecated ")]]=222;    
    addNum1(12,22,x);
    cout<<x<<endl;
    cout<<y<<endl;
    dfunc();
    volatile int a = 0; // setjmp must be set to volatile as a local variable
    int result=0;
    if (setjmp(jump_buffer) <= 20) {
       addNum2(result,++a); 
    }   
}

[[carries_dependency]] indicates that the dependency chain in consumption std::memory_order is released to pass in and out of the function, which allows the compiler to skip unnecessary memory fence instructions.
This property can occur in two situations:

  1. It can be applied to parameter declarations of functions or lambda expressions, in which case it indicates that the initialization of the parameter carries dependencies on the left-to-right value conversion of the object.
  2. It can be applied to the whole function declaration, in which case it indicates that the return value carries the evaluation dependent on the function call expression.

[[fallthrough] (C++ 17) indicates that a previous case tag failed and should not be diagnosed by a compiler that failed to warn.

[[nodiscard] (C++ 17) Encourages the compiler to issue warnings if the return value is discarded

[[maybe_unused] `(C++ 17) suppresses compiler warnings for unused instances.

Keywords: Attribute Lambda

Added by veluit06 on Thu, 12 Sep 2019 16:36:09 +0300