Modern C++ Features Supported by RAD Studio Clang-enhanced C++ Compilers

From RAD Studio
Jump to: navigation, search

Go Up to Modern C++


Note: Despite RAD Studio supports C++11 and C++14, you might encounter some issues when compiling.

Contents

C++17 features supported by the Clang-enhanced compilers

The Clang-enhanced compilers for Win32 and Win64 (bcc32c/bcc32x and bcc64) implement almost all of the ISO C++17 standard.

Note: See Modern C++ Language Features Compliance Status to discover which C++17 features each RAD Studio C++ compiler supports.

Some specific features of interest in C++17 include the following:

  • Constexpr if - a great addition for compile-time expressions.
  • string_view, a useful addition for no-copy, ie cheap and fast, read-only access to a variety of string types.
  • If-init (initializing a variable in an if statement).
  • Structured bindings.
  • Inline variables

For more information on C++17:

C++14 features supported by the Clang-enhanced compilers

The Clang-enhanced compilers for Win32 and Win64 (bcc32c/bcc32x and bcc64) implement almost all of the ISO C++14 standard.

Note: See Modern C++ Language Features Compliance Status to discover which C++14 features each RAD Studio C++ compiler supports.

Some specific features of interest in C++14 include the following:

For more information on C++14:

C++11 features supported by the Clang-enhanced compilers

Here is the list of C++11 features that are supported by the RAD Studio Clang-enhanced C++ Compilers.

Note: See Modern C++ Language Features Compliance Status to discover which C++11 features each RAD Studio C++ compiler supports.
  • Bcc32c and bcc32x (Clang-enhanced compiler for Win32) implements all of the ISO C++11 standard.
  • Older Clang-enhanced C++ compilers partially support the C++11 features:
    • Core C++11 features typically work with BCCIOSARM64. This includes variadic templates, static assertions, multi-declarator auto, lambda expressions, and others.
    • Standard (Run-time) C++11 features are typically not supported by BCCIOSARM64. This includes the initialization of class objects by rvalues, Atomic operations, and others.
  • BCC32 also supports the C++11 features described in C++11 Features in the Classic Compiler.
Note: When using the keywords specific to C++11, such as nullptr, noexcept, and so on (see http://en.cppreference.com/w/cpp/keyword for complete list), RAD Studio IDE always recognizes these keywords, but the C++ previous-generation compiler (BCC32) return a compilation error. Please note that only Clang-enhanced C++ compilers support the C++11 standard.

Rvalue references description

rvalue references is a feature supported by both BCC32 and the Clang-enhanced C++ compilers.

For more information about this feature, see rvalue References.

Rvalue references for *this

rvalue references for *this is a C++11 feature that is intended to extend the benefits of move semantics to the implicit *this parameter.

For more information on this feature, see Rvalue references for *this Proposal document.

Initialization of class objects by rvalues

C++11 standard introduces the ability to initialize class objects by rvalues, to write clear, concise, and efficient code.

This means that temporaries are now initialized directly from the entire rvalue object, instead of calling a constructor to copy the object into the temporary.

For more information about this feature, see Initialization of class objects by rvalues Proposal document .

Non-static data member initializers

C++11 introduces the possibility of initializing non-static data members within the class declaration.

The initializers for non-static data members are limited to =initializer-clause and {initializer-list}.

For more information on this feature, see the example below or the proposal document at Non-static data member initializers Proposal document.

Non-static data member initializers example

#include <string>

struct B {
        B(int, double, double);
};

class A {
        int a = 7; // OK
        std::string str1 = "member"; // OK
        B b = {1, 2, 3.0}; //OK
        std::string str2("member");   // ill-formed
};

Variadic templates

Variadic templates refer to class or function templates that can have a variable number of parameters.

In order to achieve this, C++11 introduces parameter packs to represent a list of zero or more parameters.

For more information on this feature, see Variadic templates Proposal document.

Variadic templates example

This is a small example showing the C++ syntax of variadic templates.

template<class ... T>
class A {
        // template class body
};

template<char ... T>
class B {
        // template class body
};

A<>a1;
A<int, char>a2;
A < B < 'a' >> a3;

B<>b1;
B < 'a', 'b' > b2;

Extending variadic template template parameters

During real-world experimentation with variadic templates, some limitations regarding template template parameters were uncovered.

C++11 standard extends the variadic template template parameters in order to resolve this issue.

For more information on this feature, see Extending Variadic Template Template Parameters Proposal document.

Initializer lists

Initializer lists is a feature that has been extended in C++11 standard.

An initializer list represents a list of ordered arguments, in curly brackets, that is used to initialize structures, classes, and arrays.
Until C++11, only classes that conformed to the Plain Old Data (POD) definition could be initialized using initializer lists. Now, classes like std::vector can also be initialized using initializer lists. This is done by using a template named std::initializer_list<> that can be passed as an argument to constructors or other functions.

Static assertions

Static assertions is a feature supported by both BCC32 and the Clang-enhanced C++ compilers.

For more information about this feature, see Static Assertions (C++11).

auto-typed Variables

auto-typed variables is a C++11 feature that allows the programmer to declare a variable of type auto, the type itself being deduced from the variable's initializer expression. The auto keyword is treated as a simple type specifier (that can be used with * and &), and its semantics are deduced from the initializer expression.

For more information about this feature, please see the C++11 standard Proposal Document at: auto-typed variables Proposal Document.

auto-typed Variables Examples

int IntFunc() {}
bool BoolFunc() {}
char* CharSFunc() {}

int _tmain(int argc, _TCHAR* argv[]) {
        // x is int
        auto x = IntFunc();
        // y is const bool
        const auto y = BoolFunc();
        // w is char*
        auto w = CharSFunc();
        return 0;
}

Another example of the auto type is here: Generic vector sort (C++).

Multi-declarator auto

The C++11 standard includes the multi-variable form of auto declarations, such as:

int* func(){}

int _tmain(int argc, _TCHAR* argv[])
{
        auto x = 3, * y = func(), z = 4;
        return 0;
}

The restriction with multi-declarator auto expressions is that the variables must have the same base type.

For example, the following line of code is well-formed:

auto x = 3, y = new int;

because x and y have the same base type : int, while the following code:

auto x = 3, y = 3.5;

will generate the error: [bcc64 Error] File1.cpp(11): 'auto' deduced as 'int' in declaration of 'x' and deduced as 'double' in declaration of 'y'

This feature is supported by the Clang-enhanced C++ compilers.

For more information on this feature, please see the C++11 standard Proposal Document at: Multi-declarator auto

Removal of auto as a storage-class specifier

The C++11 standard removes the use of auto as a storage class specifier entirely. This feature is supported by the Clang-enhanced C++ compilers.

If your C++ application uses auto as a storage class specifier, you will receive the following warning from Clang-enhanced C++ compilers:

Warning: "auto" storage class specifier is not permitted in C++11 and will not be supported in future releases.

For more information on this feature, please see the C++11 standard Proposal Document at: Removal of auto as a storage-class specifier.

New function declarator syntax

This C++11 feature changes the semantics of auto and introduces syntax for function declarators. The auto type-specifier signifies that the type of a variable being declared shall be deduced from its initializer expression or specified explicitly at the end of a function declarator.

For more information on this feature, please see the C++11 standard Proposal Document at : New function declarator syntax

Declared type of an expression

The declared type of an expression is a feature supported by both BCC32 and the Clang-enhanced C++ compilers.

For more information about this feature, see Type Specifier decltype (C++11).

Incomplete return types

The requirement for a function call expression's type to be complete, when used as a decltype parameter is not just unnecessary, but harmful too.

In C++11, when the parameter of a decltype expression is a function call expression returning a class type, the type is not required to be complete. Also, a temporary object is not introduced for the return value, saving storage space, and not invoking the destructor.

For more information on this feature, see Incomplete return types Proposal document.

Right angle brackets

In the Clang-enhanced C++ compilers, two consecutive right angle brackets no longer generate an error, and these constructions are treated according to the C++11 standard.

For more information, see the C++11 proposal document at Right angle brackets Proposal document.

Right angle brackets example

#pragma hdrstop
#pragma argsused

#include <tchar.h>
#include <stdio.h>

#include <vector>
typedef std::vector<std::vector<int> > Table;  // OK
typedef std::vector<std::vector<bool>> Flags;  // OK

int _tmain(int argc, _TCHAR* argv[]) {

        return 0;
}

Default template arguments for function templates

The impossibility of setting default template arguments for function templates has been limiting the programming style for a long time.

In C++11, such default arguments can be used.

For more information on this feature, see Default template arguments for function templates Proposal document.

Default template arguments for function templates example

template<class T = int, class U = char>
void function() {
        // function body
}

int _tmain(int argc, _TCHAR* argv[]) {
        function<>();            // OK, template arguments are -> int char
        function<int>();         // OK, template arguments are -> char
        function<char, char>();  // OK, template arguments are -> char char
        return 0;
}

Solving the SFINAE problem for expressions

C++11 standard solves the substitution failure is not an error (SFINAE) problem for expressions. This is done by allowing fully general expressions with the condition that most errors generated by these expressions are treated as SFINAE failures instead of errors.

For more information on this feature, see Solving the SFINAE problem for expressions Proposal document.

Alias templates

With the increased use of parameterized types in C++, the need for parameterized type aliases has grown. C++11 adds this feature to the standard.

For more information on this feature, see Alias templates Proposal document.

Extern templates

Extern templates is a feature supported by both BCC32 and the Clang-enhanced C++ compilers.

For more information on this feature, see Extern Templates (C++11).

Null pointer constant

C++11 introduces nullptr, the null pointer constant, in order to remove the ambiguity between 0 and a null pointer.

Although the NULL macro exists, it is insufficient because it cannot be distinguished from the integer 0 in a call to a function that has one overload with an int parameter and another with a char* parameter.

Therefore, nullptr is now a reserved word. The integer 0 will not be implicitly converted to any pointer type. The null pointer can only be converted to any pointer type.

Note: The null pointer cannot be used in an arithmetic expression, assigned to an integral value, or compared to an integral value.
Note: For more information, see Null pointer constant Proposal document.

See nullptr.

Strongly-typed enums

Strongly-typed enums is a feature supported by both BCC32 and the Clang-enhanced C++ compilers.

For more information about this feature, see Strongly Typed Enums (C++11).

Forward declarations for enums

Forward declarations for enums is a feature supported by both BCC32 and the Clang-enhanced C++ compilers.

For more information about this feature, see Forward Declaration of Enums (C++11).

Generalized constant expressions

C++11 standard generalizes the notion of constant expressions to include calls to simple functions (constexpr functions) and objects of user-defined types that are constructed from simple constructors (constexpr constructors).

A function is a constant-expression function if:

  • It returns a value (void type not allowed)
  • The function body consists of a single statement, the return statement: return expr;
  • It is declared with the keyword constexpr.

A variable or a data member is a constant-expression value if:

  • It is declared with the keyword constexpr
  • It is initialized with a constant expression or an rvalue constructed by a constant-expression constructor with constant-expression arguments.

A constructor is a constant-expression constructor if:

  • It is declared with the keyword constexpr
  • The member-initializer part involves only potential constant expressions
  • Its body is empty.

Generalized constant expressions example

The following example contains a constexpr function, a constexpr variable, and a constexpr constructor:

constexpr int add(int x, int y) {
        return x + y;
}
constexpr double var = 2 * add(3, 4);

class A {
        constexpr A(int newA, int newB) : a(newA), b(newB) {
        }

private:
        int a;
        int b;
};

Alignment support

C++11 standard intends to extend the standard language and library with alignment-related features.

These alignment features include:

  • Alignment specifier (alignas) to declarations
  • alignof expression to retrieve alignment requirements of a type
  • Alignment arithmetic by library support
  • Standard function (std::align) for pointer alignment at run time.

For more information on this feature, see Alignment support Proposal document.

Delegating constructors

C++11 introduces the possibility of delegating constructors. This means that class constructors can be invoked within other constructors of the same class.

This is a very useful feature that helps programmers to write less and more expressive code.

For more information about this feature, see Delegating constructors Proposal document.

Delegating constructors example

The following example shows how delegating constructors can be used:

class B {
        B(int newA) : a(newA) { /* other initializations */
        }

public:
        B() : B(15) { /* other initializations */
        }

public:
        int a;
};

Explicit conversion operators

With C++11, explicit-qualified conversion functions work in the same context as explicit-qualified constructors and produce diagnostics in the same contexts as constructors do. This is done in order to avoid situations when the compiler uncomplainingly accepts code that is not semantically correct.

For more information on these features, see Explicit conversion operators Proposal document.

New character types

C++11 introduces new character types to manipulate Unicode character strings.

For more information on this feature, see Unicode Character Types and Literals (C++11).

Unicode string literals

C++11 introduces new character types to manipulate Unicode string literals.

For more information on this feature, see Unicode Character Types and Literals (C++11).

Raw string literals

Universal character names in literals

In order to make the C++ code less platform-dependent, C++11 lifts the prohibitions regarding control and basic source universal character names within character and string literals. Prohibitions against surrogate values in all universal character names are added.

For more information on this feature, see Universal character names in literals Proposal document.

User-defined literals

C++11 introduces new forms of literals using modified syntax and semantics in order to provide user-defined literals.

Using user-defined literals, user-defined classes can provide new literal syntax.

For more information on this feature, see User-defined literals Proposal document.

Standard Layout Types

C++11 separates trivial special member requirements from layout requirements in order to create a cleaner specification.

POD (Plain Old Data) types are now defined in terms of two new categories: trivial types and standard-layout types. In C++11 standard-layout types are allowed to have base classes. However, the base classes are not allowed to have virtual members or virtual bases. Also, standard-layout types are allowed to have access control.

For more information on this feature, see Standard Layout Types Proposal document.

Defaulted functions

A defaulted function is a function that contains =default; in its prototype. This construction indicates that the function's default definition should be used.

Defaulted functions are a C++11 specific feature.

For more information on defaulted functions, see Defaulted functions Proposal document.

Defaulted functions example

class A {
        A() = default;                    // OK
        A& operator = (A & a) = default;  // OK
        void f() = default;               // ill-formed, only special member function may default
};

Deleted functions

A deleted function is a function that contains =delete; in its prototype. This construction, introduced with C++11, indicates that the function may not be used.

This construction can be used to forbid the usage of default language facilities (like default constructors or default operators) or problematic conversions.

For more information on this feature, see Deleted functions Proposal document.

Deleted functions example

class A {
        A() = delete;
        A& operator = (A & a) = delete;
};

Extended friend declarations

C++11 extends the current language to support a wider range of friend declarations.

For more information on this feature, see Extended friend declarations Proposal document.

Extending sizeof

C++11 extends the functionality of sizeof so that class members can be sent as parameters even if no object has been instantiated.

For more information on this feature, see Extending sizeof Proposal document.

Extending sizeof example

The following code represents a simple example of how sizeof can now be used.

#pragma hdrstop
#pragma argsused

#include <tchar.h>
#include <stdio.h>

class A {
public:
        int a;
};

int _tmain(int argc, _TCHAR* argv[]) {
        // no object of type A has been instantiated
        int c = sizeof(A::a);
        // well-formed
        return 0;
}

Inline namespaces

C++11 standard allows the inline keyword in a namespace-definition. This is done in order to specify that members of the namespace can be defined and specialized as though they actually belong to the enclosing namespace.

This construction is called inline namespace and solves the problem where templates could only be specialized in their actual namespace, and not in the namespace they have been imported.

For more information on this feature, see Inline namespaces Proposal document.

Unrestricted unions

The C++11 standard loosens up the restriction regarding members of unions. So, in Clang-enhanced C++ compilers, all types can be union members, except reference types.

For more information on this feature, see Unrestricted unions Proposal document.

Local and unnamed types as template arguments

The C++11 standard allows users to use local and unnamed types as template arguments.

For more information on this feature, see Local and unnamed types as template arguments Proposal document.

Range-based for

Range-based is a feature introduced by the C++11 standard.

In Clang-enhanced C++ compilers, you can create for loops that iterate through a list or an array without computing the beginning, the end, or using an iterator.

The following example shows the range-based for syntax for a string:

UnicodeString string("C++11");
for (auto character : string) {
    std::wcout << character;		
}

Explicit virtual overrides

Regarding virtual overrides, C++11 tends to tighten the rules, to detect some problems that often arise.

To achieve this goal C++11 introduces two new contextual keywords:

  • final specifies that a method cannot be overridden or a class cannot be derived.
  • override specifies that a method overrides a virtual method declared in one of its parent classes.

For more information on this feature, see Explicit virtual overrides Proposal document.

Explicit virtual overrides example

struct base {
        virtual void a();
        void b();
        virtual void c() final;
        virtual void d();
};

struct derived : base {
        void a() override; // correct
        void b() override; // error, an override can only be used for virtual functions
        void c() override; // error, cannot override a function marked as final
        int d() override; // error, different return type
};

Allowing move constructors to throw [noexcept]

The C++11 standard provides an alternative to std::move, which is std::move_if_noexcept, to solve some problematic interactions between move constructors, templates, and certain standard library member functions.

std::move_if_noexcept(x) grants permission to move x unless it could throw and the type can be copied.

For more information on this feature, see Allowing move constructors to throw Proposal document.

Defining move special member functions

C++11 provides a way of defining move and copy special member functions.

For more information on this feature, see Defining move special member functions Proposal document.

Atomic operations

C++11 adds atomic types and operations to the standard. Atomic types and operations provide a way of writing multi-threaded applications without using locks.

For more information on this feature, see Atomic operations Proposal document.

Strong Compare and Exchange

C++11 provides both weak and strong compare-and-exchange operations.

Compare-and-exchange operation is an atomic operation used in multi-threaded applications to achieve synchronization.

For more information on this feature, see Strong Compare and Exchange Proposal document.

Bidirectional Fences

A fence is a primitive that enforces ordering between preceding loads or stores and subsequent loads or stores. C++11 improves the support for bidirectional fences.

For more information on this feature, see Bidirectional Fences Proposal document.

Propagating exceptions

The C++11 standard offers the possibility of moving an exception from one thread to another. To do that, some modifications have been made to the <exception> header.

For more information on this feature, see Propagating exceptions Proposal document.

Allow atomics use in signal handlers

C++11 allows the use of atomics in signal handlers.

For more information on this feature, see Allow atomics use in signal handlers Proposal document.

__func__ predefined identifier

This feature is used to capture function names as string literals and to assist diagnostic libraries.

For more information on this feature, see __func__ predefined identifier Proposal document.

C99 preprocessor

The C++11 standard intends to resynchronize the preprocessor and translation phases of C++ with C99, to make the two standards more compatible.

Predefined macros, pragma operators, and string literal concatenation are some areas in which changes were made.

For more information on this feature, see C99 preprocessor Proposal document.

long long type

To be more compatible with C99, C++11 standard introduces the long long integral type.

For more information on this feature, see long long type Proposal document.

Other Features

See Also