close
Namespaces
Variants

Splice specifiers (since C++26)

From cppreference.com
 
 
C++ language
General topics
Flow control
Conditional execution statements
if
Iteration statements (loops)
for
range-for (C++11)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications (until C++17*)
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
explicit (C++11)
static

Special member functions
Templates
Miscellaneous
 
 

Produces a language construct from a reflection value, effectively "splicing" the reflection into source code.

Syntax

[: constant-expression :] (1)
typename [: constant-expression :] (2)
template [: constant-expression :] (3)
constant-expression - a converted constant expression of type std::meta::info
1) A splice specifier whose meaning depends on the context.
2) A splice specifier that is a type specifier.
3) A splice specifier that designates a template. If it does not appear as an expression, the specifier must be followed by a template argument list (enclosed in <>), and must be the left operand of the scope resolution operator ::, e.g. template[:R:]<int>::is_always_lock_free.

Explanation

In general, a splice specifier has the same meaning as the name or value of the language construct represented by constant-expression. It is said to designate that language construct.

Expression

For a splice specifier to be an expression, the specifier must not follow the typename keyword, nor be followed by the scope resolution operator ::.

struct S { static constexpr int a = 1; };
template<typename> struct TCls { static constexpr int b = 2; };

constexpr int c = [:^^S:]::a; // [:^^S:] is not an expression
constexpr int d = template [:^^TCls:]<int>::b; // template [:^^TCls:]<int> is not an expression
template<auto V> constexpr int e = [:V:]; // [:V:] is an expression
constexpr int f = template [:^^e:]<^^S::a>; // template [:^^e:]<^^S::a> is an expression

constexpr auto g = typename [:^^int:](42); // typename [:^^int:] is a type specifier

An unparenthesized splice expression cannot appear as a template argument.

A splice expression can designates a function, an object, a data member, a variable, a structured binding, a value, or an enumerator. But it cannot designate a constructor, a destructor, an unnamed bit-field, or a local entity such that naming it would cause it to be captured by a lambda expression.

A splice expression that designates a variable or structured binding V is valid only if V has static or thread storage duration or is declared in a scope enclosing the expression.

A splice expression that designates a non-static data member or implicit object member function can only be used:

Unlike names of non-static members, a splice expression [:r:] is never implicitly transformed to this->[:r:].

A splice expression [:r:] may describe a direct base class relationship (D, B) (e.g. if r is an element of std::meta::bases_of(^^D, ctx)). A direct base class relationship can only appear as the second operand of class member access expression. This class member access expression converts the first operand to “reference to (possibly cv-qualified) D” and results in the B direct base class subobject of the converted value. This can be used to access a base class subject that would otherwise be ambiguous or inaccessible.

A splice expression can designate a function template or variable template only if the template keyword is used.

Type

A splice specifier that is a type specifier must not be followed by the scope resolution operator ::, and must either be preceded by typename, or be in a type-only context.

template<std::meta::info R> void tfn() {
    typename [:R:]::type m; // OK, typename applies to the qualified name
                            // (Here [:R:] is a scope, not a type specifier.)
}
struct S { using type = int; };

void fn() {
    [:^^S::type:] *var; // error: [:^^S::type:] is an expression
    typename [:^^S::type:] *var; // OK, declares variable with type int*
}

using alias = [:^^S::type:]; // OK, type-only context

A splice type specifier can designate a type, a class template, or an alias template. If it designates a template and does not have a template argument list, it is subject to class template argument deduction.

A splice specifier may also appear in a type requirement.

template<typename T> concept C = requires {
    typename [:T::r1:]; // fails if T::r1 is not a reflection of a type
    typename [:T::r2:]<int>; // fails if T::r2 is not a reflection of some template Z
                             // for which Z<int> is a type
};

Scope

For a splice specifier that is the left operand of the the scope resolution operator ::, if the specifier has a template argument list, it must be preceded by typename or template.

template<int V>
struct TCls {
    static constexpr int s = V;
    using type = int;
};

int v1 = [:^^TCls<1>:]::s;
int v2 = template [:^^TCls:]<2>::s; // OK, 'template' is part of the splice specifier
typename [:^^TCls:]<3>::type v3 = 3; // OK, 'typename' is part of the typename-specifier
template [:^^TCls:]<3>::type v4 = 4; // OK, 'template' is part of the splice specifier
typename template [:^^TCls:]<3>::type v5 = 5; // OK, same as v3
[:^^TCls:]<3>::type v6 = 6; // error: unexpected <

The splice specifier must designate a class or enumeration type, or a namespace. The splice specifier in [:r:]<TArgs...>:: or template[:r:]<TArgs...>:: must designate a class template or alias template.

Namespace

A splice specifier [:r:] in a namespace alias definition or a using directive must designate a namespace name or namespace alias that is not the global namespace. A dependent r can appear in a namespace alias definition (but not in a using directive), which causes the namespace alias to be dependent as well.

Example

See also