\begin{ccppspecific}[4ex] \section{C/C++ Attributes} \label{sec:attributes} \index{directive syntax!attribute, C/C++} \index{attribute syntax, C/C++} OpenMP directives for C/C++ can also be specified with the \kcode{directive} extension for the C23 and C++11 standard \plc{attributes}. %https://en.cppreference.com/w/cpp/language/attributes The example below shows two ways to parallelize a \bcode{for} loop using the \kcode{\#pragma} syntax. The first pragma uses the combined \kcode{parallel for} directive, and the second applies the uncombined closely nested directives, \kcode{parallel} and \kcode{for}, directly to the same statement. These are labeled PRAG 1-3. Using the attribute syntax, the same construct in PRAG 1 is applied in two different ways in attribute form, as shown in the ATTR 1 and ATTR 2 sections. In ATTR 1 the attribute syntax is used with the \kcode{omp ::} namespace form. In ATTR 2 the attribute syntax is used with the \kcode{using omp :} namespace form available for C++ only. Next, parallelization is attempted by applying directives using two different syntaxes. For ATTR 3 and PRAG 4, the loop parallelization will fail to compile because multiple directives that apply to the same statement must all use either the attribute syntax or the pragma syntax. The lines have been commented out and labeled INVALID. While multiple attributes may be applied to the same statement, compilation may fail if the ordering of the directive matters. For the ATTR 4-5 loop parallelization, the \kcode{parallel} directive precedes the \kcode{for} directive, but the compiler may reorder consecutive attributes. If the directives are reversed, compilation will fail. The attribute directive of the ATTR 6 section resolves the previous problem (in ATTR 4-5). Here, the \kcode{sequence} attribute is used to apply ordering to the directives of ATTR 4-5, using the \kcode{omp ::} namespace qualifier. (The \kcode{using omp :} namespace form is not available for the \kcode{sequence} attribute.) Note, for the \kcode{sequence} attribute a comma must separate the \kcode{directive} extensions. The last 3 pairs of sections (PRAG DECL 1-2, 3-4, and 5-6) show cases where directive ordering does not matter for \kcode{declare simd} directives. In section PRAG DECL 1-2, the two loops use different SIMD forms of the \ucode{P} function (one with \kcode{simdlen(\ucode{4})} and the other with \kcode{simdlen(\ucode{8})}), as prescribed by the two different \kcode{declare simd} directives applied to the \ucode{P} function definitions (at the beginning of the code). The directives use the pragma syntax, and order is not important. For the next set of loops (PRAG DECL 3-4) that use the \ucode{Q} function, the attribute syntax is used for the \kcode{declare simd} directives. The result is compliant code since directive order is irrelevant. Sections ATTR DECL 5-6 are included for completeness. Here, the attribute form of the \kcode{simd} directive is used for loops calling the \ucode{Q} function, in combination with the attribute form of the \kcode{declare simd} directives declaring the variants for \ucode{Q}. \topmarker{C/C++} \cppnexample[6.0]{directive_syntax_attribute}{1} \topmarker{C/C++} The following code snippets show how to use the \kcode{omp::decl} attribute as an alternative way for specifying declarative directives. The \kcode{omp::decl} attribute can be embedded in the base language declarations as shown for variables in Cases 1 and 2, for function in Case 3, and for C++ template in Case 4. The variable and function name lists are implied from where the attributes are specified. In Case 1, the prefix attribute applies to all variables (\ucode{u} and \ucode{v}) in the declaration; in Case 2, the postfix attribute applies to the associated variable (\ucode{a} as the directive argument for the \kcode{declare_target} directive, and \ucode{b} as the clause argument for the \kcode{link} clause on \kcode{declare_target}); in Case 3, the prefix attribute applies to the function (\ucode{f}). The comma to separate directive name (\kcode{declare_target}) and clause name (\kcode{link}) in the \kcode{omp::decl} attribute specifier in Case 2 is optional. Case 4 shows the use of \kcode{omp::decl(declare_target)} for a C++ template function definition and its equivalent using the delimited \kcode{begin}/\kcode{end declare_target} pragma form. \cppnexample[6.0]{directive_syntax_attribute}{2} \end{ccppspecific}