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.

Notes

In addition to splice specifiers, the function templates std::meta::extract and std::meta::substitute can also turn a reflection to the value it represents. Unlike splice specifiers, they do not require the arguments to be constant expressions in isolation, but have different restrictions.

Example

See also

Morty Proxy This is a proxified and sanitized view of the page, visit original site.