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 of the language construct represented by constant-expression. If constant-expression represents a type alias or a namespace alias, the splice specifier designates the type or namespace.

Expression

For a splice specifier to be an expression, the specifier must not follow the typename keyword, nor be an operand of 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

For a splice expression of the form [:r:]:

  • The expression is invalid if r represents:
  • a constructor,
  • a destructor,
  • an unnamed bit-field, or
  • a local entity such that replacing the expression with the entity's name would cause the entity to be captured by a lambda expression.
  • Otherwise, if r represents a function F, the expression denotes an overload set containing all preceding declarations of F. Overload resolution is performed.
  • Otherwise, if r represents an object or a non-static data member, the expression is an lvalue denoting the object or member.
  • Otherwise, if r represents a direct base class relationship (that is, r is an element of std::meta::bases_of(^^D, ctx) for some class D), the expression designates the relationship. Such an expression can only appear as the right operand of a class member access.
  • Otherwise, if r represents a variable or a structured binding, the variable or structured binding must either have static or thread storage duration or be declared in a scope enclosing the expression. The expression is an lvalue referring to the object or function named by or referenced by the variable or structured binding.
  • Otherwise, if r represents a (constant) value or an enumerator, the expression is a prvalue that computes the value or enumerator.
  • Otherwise, the expression is invalid.

For a splice expression of the form template[:r:] (without a template argument list):

  • r must represent a function template FT that is not a constructor template. The expression denotes an overload set containing all preceding declarations of the FT. Overload resolution is performed.

For a splice expression of the form template[:r:]<TArgs...>:

  • If r represents a function template FT, the expression denotes an overload set containing all preceding declarations of FT. Overload resolution is performed.
  • Otherwise, r must represent a variable template VT. The expression is an lvalue referring to the object or function associated with VT<TArgs...>.

Type

For a splice specifier to be a type specifier, the specifier must not be an operand of the scope resolution operator ::. If not preceded by typename, the specifier must be in a type-only context.

template<std::meta::info R> void tfn() {
    typename [:R:]::type m; // OK, typename applies to the qualified name
}
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

For a splice type specifier of the form [:r:] or typename [:r:](without a template argument list):

  • r must represent a type, a type alias, a class template, or an alias template. The type specifier designates the same type or template as the entity represented by r. (If r represents a deducible template, class template argument deduction may apply.)

For a splice type specifier of the form [:r:]<TArgs...> or typename[:r:]<TArgs...>:

  • r must represent a class template or alias template TT. The type specifier designates the type TT<TArgs...>.

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 reflection r in [:r:]:: must represent a class or enumeration type, a type alias thereof, or a namespace. The reflection r in [:r:]<TArgs...>:: or template[:r:]<TArgs...>:: must represent a class template or alias template. The splice specifier designates the same type, namespace, or template as the entity represented by r.

Namespace

For a splice specifier [:r:] in a namespace alias definition or a using directive, r must represent a namespace name or namespace alias that is not the global namespace. The splice specifier designates the same namespace as the entity represented by r.

Example

See also