Splice specifiers (since C++26)
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 |
<>), 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
rrepresents:
- 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
rrepresents a functionF, the expression denotes an overload set containing all preceding declarations ofF. Overload resolution is performed. - Otherwise, if
rrepresents an object or a non-static data member, the expression is an lvalue denoting the object or member. - Otherwise, if
rrepresents a direct base class relationship (that is,ris an element ofstd::meta::bases_of(^^D, ctx)for some classD), the expression designates the relationship. Such an expression can only appear as the right operand of a class member access. - Otherwise, if
rrepresents 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
rrepresents 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):
rmust represent a function templateFTthat is not a constructor template. The expression denotes an overload set containing all preceding declarations of theFT. Overload resolution is performed.
For a splice expression of the form template[:r:]<TArgs...>:
- If
rrepresents a function templateFT, the expression denotes an overload set containing all preceding declarations ofFT. Overload resolution is performed. - Otherwise,
rmust represent a variable templateVT. The expression is an lvalue referring to the object or function associated withVT<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):
rmust 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 byr. (Ifrrepresents a deducible template, class template argument deduction may apply.)
For a splice type specifier of the form [:r:]<TArgs...> or typename[:r:]<TArgs...>:
rmust represent a class template or alias templateTT. The type specifier designates the typeTT<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
| This section is incomplete Reason: no example |