I will show in this article some tips and tricks using the new C++17. For the tests I used Clang version 5.0 and GCC 7.2 maybe in previous versions will not work. C++17 is more intuitive and definitely a more modern and productive programming language.
See example:
#include <cstdint>
struct CType
{
uint32_t value;
};
// C++17.
struct Derived : CType
{
int status;
void f();
};
int main(void)
{
// C++17 Init.
Derived d{ {42}, 1 };
// C++17 Init.
Derived e{ {}, 0};
return 0;
}
To compile the example:
clang++-devel -std=c++1z aggregate.cpp -o aggregate && ./aggregate
Run on GCC 7 using Compiler Explorer: aggregate
In static_assert it is no longer necessary to pass the error message as parameter, the automatic message already exists. If an assert violation occurs at the time of compilation the error is already automatically captured.
See example:
int main(void)
{
// C++17.
static_assert(sizeof(int) >= 4);
// C++17.
static_assert(2 + 2 == 4);
return 0;
}
To compile the example:
clang++-devel -std=c++1z assert.cpp -o assert && ./assert
Run on GCC 7 using Compiler Explorer: assert
You can apply this function to search for arguments:
See example:
#include <initializer_list>
#include <utility>
#include <iostream>
template <class F, class ... Ts>
void for_each_argument(F f, Ts&&... a) {
(void)std::initializer_list<int>{(f(std::forward<Ts>(a)), 0)...};
}
int main(void)
{
for_each_argument([](const auto &arg){ std::cout << arg << "\n"; }, 1, 2, 3, 4, 5);
return 0;
}
To compile the example:
clang++-devel -std=c++1z for_each_argument.cpp -o for_each_argument && ./for_each_argument
Run on GCC 7 using Compiler Explorer: for_each_argument
Static variables inline, no longer need to be initialized in the source file, can initialized directly into the class.
See example:
// class_global_static.hpp
#include <iostream>
class Log
{
private:
static inline bool m_log = false;
public:
static void setEnabled(bool log = false) {
m_log = log;
}
Log() {
if (m_log)
std::cout << "Hi! log is enabled.\n";
}
};
int main(void)
{
Log::setEnabled(true);
Log lg;
return 0;
}
To compile the example:
clang++-devel -std=c++1z class_global_static.cpp -o class_global_static && ./class_global_static
Run on GCC 7 using Compiler Explorer: class_global_static
Using lambda to catch this class.
See example:
#include <iostream>
#include <string>
class A {
private:
std::string m_name;
public:
void test() {
// C++17 create local copy from this.
[*this] { std::cout << m_name << std::endl; };
[this] { std::cout << m_name << std::endl; };
[=] { std::cout << m_name << std::endl; };
[&] { std::cout << m_name << std::endl; };
}
};
int main(void)
{
A a;
a.test();
return 0;
}
To compile the example:
clang++-devel -std=c++1z lambda_this.cpp -o lambda_this && ./lambda_this
Run on GCC 7 using Compiler Explorer: lambda_this.cpp
The __has_include function can be used to test whether an include exists and also helps with application portability.
See example:
#if __has_include(<optional>)
#include <optional>
#define DIAGNOSTIC_TYPE = 1
#endif __has_include(<proto>)
#include <proto>
#define DIAGNOSTIC_TYPE = 2
#else
#define DIAGNOSTIC_TYPE = 3
#endif
With C++17 you can initialize the namespace directly.
See example:
#include <iostream>
// C++98.
namespace A {
namespace B {
namespace C {
}
}
}
// C++17.
namespace A::B::C {
static void hello() {
std::cout << "Hello, C++17 namespace\n";
}
}
int main(void)
{
A::B::C::hello();
return 0;
}
To compile the example:
clang++-devel -std=c++1z namespace.cpp -o namespace && ./namespace
Run on GCC 7 using Compiler Explorer: namespace.cpp
Introduced under proposal P0144R0, Structured Bindings give us the ability to declare multiple variables initialised from a tuple or struct.
See example:
#include <iostream>
#include <tuple>
int main(void)
{
auto tuple = std::make_tuple(1, 'A', 2.3);
auto& [a, b, c] = tuple;
std::cout << "a=" << a << ", b=" << b << ", c=" << c << '\n';
a = 2;
std::cout << std::get<0>(tuple) << '\n';
return 0;
}
To compile the example:
clang++-devel -std=c++1z tuple.cpp -o tuple && ./tuple
Run on GCC 7 using Compiler Explorer: tuple.cpp
Using template class with arguments and initializing.
See example:
#include <iostream>
template <typename T1, typename T2>
class Test {
public:
explicit Test (T1 x = T1(), T2 y = T2())
{
std::cout << "X=" << x << " Y=" << y << "\n";
}
};
int main(void)
{
// C++98.
Test<int, double> a1;
// C++17
Test a("Hello", 10);
}
To compile the example:
clang++-devel -std=c++1z template.cpp -o template && ./template
Run on GCC 7 using Compiler Explorer: template.cpp