convert some ::value to _v - #10765
Conversation
📝 WalkthroughSummary by CodeRabbit
WalkthroughChangesThe patch replaces legacy trait Trait modernization
Suggested reviewers: Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: db93125b-7d19-4ac6-ba8d-7128f990bf42
📒 Files selected for processing (17)
libcudacxx/include/cuda/__complex/traits.hlibcudacxx/include/cuda/__functional/address_stability.hlibcudacxx/include/cuda/std/__algorithm/equal_range.hlibcudacxx/include/cuda/std/__algorithm/includes.hlibcudacxx/include/cuda/std/__algorithm/lower_bound.hlibcudacxx/include/cuda/std/__algorithm/min_element.hlibcudacxx/include/cuda/std/__algorithm/minmax.hlibcudacxx/include/cuda/std/__algorithm/minmax_element.hlibcudacxx/include/cuda/std/__algorithm/stable_sort.hlibcudacxx/include/cuda/std/__simd/utility.hlibcudacxx/include/cuda/std/__tuple_dir/tuple_like.hlibcudacxx/include/cuda/std/__type_traits/add_pointer.hlibcudacxx/include/cuda/std/__type_traits/is_copy_assignable.hlibcudacxx/include/cuda/std/__type_traits/is_copy_constructible.hlibcudacxx/include/cuda/std/__type_traits/is_destructible.hlibcudacxx/include/cuda/std/__type_traits/is_move_constructible.hlibcudacxx/include/cuda/std/__type_traits/is_nothrow_destructible.h
|
|
||
| template <typename _Range> | ||
| inline constexpr bool __has_tuple_size_v<_Range, void_t<decltype(tuple_size<remove_cvref_t<_Range>>::value)>> = true; | ||
| inline constexpr bool __has_tuple_size_v<_Range, void_t<decltype(tuple_size_v<remove_cvref_t<_Range>>)>> = true; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
for f in \
libcudacxx/include/cuda/std/__simd/utility.h \
libcudacxx/include/cuda/__complex/traits.h \
libcudacxx/include/cuda/std/__tuple_dir/tuple_like.h
do
echo "===== $f ====="
wc -l "$f"
sed -n '1,125p' "$f"
done
echo "===== tuple_size and tuple_size_v definitions/usages ====="
rg -n --glob '*.{h,hpp,cpp,cc,cxx,cu,cuh}' \
'tuple_size_v|tuple_size<|__has_tuple_size_v|__is_complex_compatible_tuple_like|__pair_like' \
libcudacxx | head -250
echo "===== current diff summary ====="
git diff --stat -- \
libcudacxx/include/cuda/std/__simd/utility.h \
libcudacxx/include/cuda/__complex/traits.h \
libcudacxx/include/cuda/std/__tuple_dir/tuple_like.h
echo "===== current diff for the three files ====="
git diff -- \
libcudacxx/include/cuda/std/__simd/utility.h \
libcudacxx/include/cuda/__complex/traits.h \
libcudacxx/include/cuda/std/__tuple_dir/tuple_like.hRepository: NVIDIA/cccl
Length of output: 38810
🏁 Script executed:
#!/bin/bash
set -eu
echo "===== tuple_size implementation ====="
cat -n libcudacxx/include/cuda/std/__tuple_dir/tuple_size.h | sed -n '1,115p'
echo "===== constraint macro definitions ====="
rg -n -A18 -B8 \
'_CCCL_REQUIRES_EXPR|define _CCCL_REQUIRES_EXPR|_CCCL_CONCEPT' \
libcudacxx/include/cuda/std/__concepts/concept_macros.h \
libcudacxx/include/cuda/std/__concepts 2>/dev/null | head -220
echo "===== related tuple-like and complex tests ====="
rg -n -A12 -B8 \
'__pair_like|__is_complex_compatible_tuple_like|incomplete|tuple_size_v' \
libcudacxx/test/libcudacxx/cuda/complex \
libcudacxx/test/libcudacxx/std/utilities/tuple/tuple.tuple/tuple.helper \
libcudacxx/test/libcudacxx/std/ranges 2>/dev/null | head -300
echo "===== recent history for the affected files ====="
git log --oneline -12 -- \
libcudacxx/include/cuda/std/__simd/utility.h \
libcudacxx/include/cuda/__complex/traits.h \
libcudacxx/include/cuda/std/__tuple_dir/tuple_like.h
echo "===== available C++ compilers ====="
command -v g++ || true
command -v clang++ || true
command -v nvcc || trueRepository: NVIDIA/cccl
Length of output: 50367
🏁 Script executed:
#!/bin/bash
set -eu
echo "===== available C++ compilers ====="
command -v g++ || true
command -v clang++ || true
command -v nvcc || true
echo "===== focused concept macro sections ====="
sed -n '35,72p;201,225p;229,290p' libcudacxx/include/cuda/std/__concepts/concept_macros.h
echo "===== focused history ====="
git log --oneline -12 -- libcudacxx/include/cuda/std/__simd/utility.h
git log --oneline -12 -- libcudacxx/include/cuda/__complex/traits.h
git log --oneline -12 -- libcudacxx/include/cuda/std/__tuple_dir/tuple_like.h
echo "===== commits that introduced the tuple-size spellings ====="
git log --all --oneline -S'tuple_size_v<remove_cvref_t<_Range>>' -- libcudacxx/include/cuda/std/__simd/utility.h || true
git log --all --oneline -S'tuple_size_v<_Tp>' -- libcudacxx/include/cuda/__complex/traits.h || true
git log --all --oneline -S'tuple_size_v<remove_cvref_t<_Tp>>' -- libcudacxx/include/cuda/std/__tuple_dir/tuple_like.h || true
echo "===== standalone compiler probe ====="
cat >/tmp/tuple-size-probe.cpp <<'CPP'
`#include` <cstddef>
`#include` <type_traits>
template <class T>
struct tuple_size;
template <class T>
inline constexpr std::size_t tuple_size_v = tuple_size<T>::value;
template <class T, class = void>
inline constexpr bool has_member_probe = false;
template <class T>
inline constexpr bool has_member_probe<T, std::void_t<decltype(tuple_size<T>::value)>> = true;
template <class T, class = void>
inline constexpr bool has_variable_probe = false;
template <class T>
inline constexpr bool has_variable_probe<T, std::void_t<decltype(tuple_size_v<T>)>> = true;
template <class T>
concept variable_constraint = requires { requires(tuple_size_v<T> == 2); };
template <class T>
concept member_constraint = requires { requires(tuple_size<T>::value == 2); };
struct Incomplete;
static_assert(!has_member_probe<Incomplete>);
static_assert(!has_variable_probe<Incomplete>);
static_assert(!member_constraint<Incomplete>);
static_assert(!variable_constraint<Incomplete>);
int main() {}
CPP
if command -v g++ >/dev/null 2>&1; then
g++ -std=c++20 -fsyntax-only /tmp/tuple-size-probe.cpp
echo "g++ probe: success"
fi
if command -v clang++ >/dev/null 2>&1; then
clang++ -std=c++20 -fsyntax-only /tmp/tuple-size-probe.cpp
echo "clang++ probe: success"
fiRepository: NVIDIA/cccl
Length of output: 8332
🏁 Script executed:
#!/bin/bash
set -u
echo "===== conversion commit ====="
git show --no-ext-diff --format=fuller --stat 8bd263c5e
git show --no-ext-diff --format= --unified=18 8bd263c5e -- \
libcudacxx/include/cuda/std/__simd/utility.h \
libcudacxx/include/cuda/__complex/traits.h \
libcudacxx/include/cuda/std/__tuple_dir/tuple_like.h
echo "===== standalone compiler probe with clang++ ====="
cat >/tmp/tuple-size-probe.cpp <<'CPP'
`#include` <cstddef>
`#include` <type_traits>
template <class T>
struct tuple_size;
template <class T>
inline constexpr std::size_t tuple_size_v = tuple_size<T>::value;
template <class T, class = void>
inline constexpr bool has_member_probe = false;
template <class T>
inline constexpr bool has_member_probe<T, std::void_t<decltype(tuple_size<T>::value)>> = true;
template <class T, class = void>
inline constexpr bool has_variable_probe = false;
template <class T>
inline constexpr bool has_variable_probe<T, std::void_t<decltype(tuple_size_v<T>)>> = true;
template <class T>
concept variable_constraint = requires { requires(tuple_size_v<T> == 2); };
template <class T>
concept member_constraint = requires { requires(tuple_size<T>::value == 2); };
struct Incomplete;
static_assert(!has_member_probe<Incomplete>);
static_assert(!has_variable_probe<Incomplete>);
static_assert(!member_constraint<Incomplete>);
static_assert(!variable_constraint<Incomplete>);
int main() {}
CPP
if command -v clang++ >/dev/null 2>&1; then
clang++ --version | head -1
clang++ -std=c++20 -fsyntax-only /tmp/tuple-size-probe.cpp
echo "clang++ probe: success"
else
echo "clang++ unavailable"
fiRepository: NVIDIA/cccl
Length of output: 8714
🏁 Script executed:
#!/bin/bash
set -u
echo "===== _CCCL_REQUIRES_EXPR definition ====="
rg -n -A12 -B8 '_CCCL_REQUIRES_EXPR' libcudacxx/include/cuda/std
echo "===== exact pair-like behavior in a standalone probe ====="
cat >/tmp/pair-like-probe.cpp <<'CPP'
`#include` <cstddef>
template <class T>
struct tuple_size;
template <class T>
inline constexpr std::size_t tuple_size_v = tuple_size<T>::value;
template <class T>
inline constexpr bool tuple_like_ext = false;
template <class T>
concept pair_like_variable = requires {
requires(tuple_like_ext<T>);
requires(tuple_size_v<T> == 2);
};
template <class T>
concept pair_like_member = requires {
requires(tuple_like_ext<T>);
requires(tuple_size<T>::value == 2);
};
struct Unsupported;
static_assert(!pair_like_variable<Unsupported>);
static_assert(!pair_like_member<Unsupported>);
int main() {}
CPP
if command -v clang++ >/dev/null 2>&1; then
clang++ -std=c++20 -fsyntax-only /tmp/pair-like-probe.cpp
rc=$?
echo "clang++ pair-like probe exit: $rc"
fi
echo "===== exact complex-style behavior in a standalone probe ====="
cat >/tmp/complex-like-probe.cpp <<'CPP'
`#include` <cstddef>
`#include` <type_traits>
template <class T>
struct tuple_size;
template <class T>
inline constexpr std::size_t tuple_size_v = tuple_size<T>::value;
template <class T>
using tuple_element_t = typename T::missing;
template <class T>
concept complex_like_variable = requires {
requires(tuple_size_v<T> == 2);
requires(std::is_same_v<tuple_element_t<T>, tuple_element_t<T>>);
};
template <class T>
concept complex_like_member = requires {
requires(tuple_size<T>::value == 2);
requires(std::is_same_v<tuple_element_t<T>, tuple_element_t<T>>);
};
struct Unsupported;
static_assert(!complex_like_variable<Unsupported>);
static_assert(!complex_like_member<Unsupported>);
int main() {}
CPP
if command -v clang++ >/dev/null 2>&1; then
clang++ -std=c++20 -fsyntax-only /tmp/complex-like-probe.cpp
rc=$?
echo "clang++ complex-like probe exit: $rc"
fiRepository: NVIDIA/cccl
Length of output: 50368
🏁 Script executed:
#!/bin/bash
set -u
echo "===== _CCCL_REQUIRES_EXPR implementation ====="
sed -n '296,322p' libcudacxx/include/cuda/std/__concepts/concept_macros.h
echo "===== pair-like probe with a recognized but incomplete tuple type ====="
cat >/tmp/pair-like-probe.cpp <<'CPP'
`#include` <cstddef>
template <class T>
struct tuple_size;
template <class T>
inline constexpr std::size_t tuple_size_v = tuple_size<T>::value;
struct RecognizedTuple;
template <>
inline constexpr bool tuple_like_ext<RecognizedTuple> = true;
template <class T>
concept pair_like_variable = requires {
requires(tuple_like_ext<T>);
requires(tuple_size_v<T> == 2);
};
template <class T>
concept pair_like_member = requires {
requires(tuple_like_ext<T>);
requires(tuple_size<T>::value == 2);
};
static_assert(!pair_like_member<RecognizedTuple>);
static_assert(!pair_like_variable<RecognizedTuple>);
int main() {}
CPP
if command -v clang++ >/dev/null 2>&1; then
clang++ -std=c++20 -fsyntax-only /tmp/pair-like-probe.cpp >/tmp/pair-like-probe.out 2>&1
rc=$?
echo "clang++ pair-like probe exit: $rc"
sed -n '1,25p' /tmp/pair-like-probe.out
fi
echo "===== direct current-header probes ====="
cat >/tmp/current-header-probe.cpp <<'CPP'
`#include` <cuda/std/__simd/utility.h>
`#include` <cuda/std/__tuple_dir/tuple_like.h>
`#include` <cuda/__complex/traits.h>
struct UnsupportedTuple;
static_assert(!::cuda::std::simd::__has_tuple_size_v<UnsupportedTuple>);
static_assert(!::cuda::std::__pair_like<UnsupportedTuple>);
static_assert(!::cuda::__is_complex_compatible_tuple_like<UnsupportedTuple>);
int main() {}
CPP
if command -v clang++ >/dev/null 2>&1; then
clang++ -std=c++20 -fsyntax-only -Ilibcudacxx/include /tmp/current-header-probe.cpp \
>/tmp/current-header-probe.out 2>&1
rc=$?
echo "clang++ current-header probe exit: $rc"
sed -n '1,45p' /tmp/current-header-probe.out
fiRepository: NVIDIA/cccl
Length of output: 7470
🏁 Script executed:
#!/bin/bash
set -u
echo "===== direct __pair_like probe with an incomplete recognized tuple ====="
cat >/tmp/pair-like-current-probe.cpp <<'CPP'
`#include` <cuda/std/__tuple_dir/tuple_like.h>
static_assert(!::cuda::std::__pair_like<::cuda::std::tuple<int, int>>);
int main() {}
CPP
if command -v clang++ >/dev/null 2>&1; then
clang++ -std=c++20 -fsyntax-only -Ilibcudacxx/include \
/tmp/pair-like-current-probe.cpp >/tmp/pair-like-current-probe.out 2>&1
rc=$?
echo "clang++ __pair_like probe exit: $rc"
sed -n '1,40p' /tmp/pair-like-current-probe.out
fi
echo "===== parent implementation of all three probes ====="
git show 8bd263c5e^:libcudacxx/include/cuda/std/__simd/utility.h | sed -n '78,86p'
git show 8bd263c5e^:libcudacxx/include/cuda/__complex/traits.h | sed -n '37,44p'
git show 8bd263c5e^:libcudacxx/include/cuda/std/__tuple_dir/tuple_like.h | sed -n '93,99p'Repository: NVIDIA/cccl
Length of output: 4870
critical: Restore member-based tuple-size probes in all three constraint paths. tuple_size_v<T> can hard-error when tuple_size<T> is incomplete instead of producing a failed constraint.
libcudacxx/include/cuda/std/__simd/utility.h:83: usedecltype(tuple_size<remove_cvref_t<_Range>>::value).libcudacxx/include/cuda/__complex/traits.h:41: use::cuda::std::tuple_size<_Tp>::value.libcudacxx/include/cuda/std/__tuple_dir/tuple_like.h:97: usetuple_size<remove_cvref_t<_Tp>>::value.
📍 Affects 3 files
libcudacxx/include/cuda/std/__simd/utility.h#L83-L83(this comment)libcudacxx/include/cuda/__complex/traits.h#L41-L41libcudacxx/include/cuda/std/__tuple_dir/tuple_like.h#L97-L97
Source: Path instructions
| template <class _Tp> | ||
| _CCCL_CONCEPT __pair_like = _CCCL_REQUIRES_EXPR((_Tp)) // | ||
| (requires(__tuple_like<_Tp>), requires(tuple_size<remove_cvref_t<_Tp>>::value == 2)); | ||
| (requires(__tuple_like<_Tp>), requires(tuple_size_v<remove_cvref_t<_Tp>> == 2)); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- tuple_like.h ---'
sed -n '70,115p' libcudacxx/include/cuda/std/__tuple_dir/tuple_like.h
printf '%s\n' '--- concept macros ---'
sed -n '1,240p' libcudacxx/include/cuda/std/__concepts/concept_macros.h
printf '%s\n' '--- related tuple_size_v usage ---'
rg -n -C 3 'tuple_size_v|__pair_like|_CCCL_REQUIRES_EXPR' libcudacxx/include/cuda/std/__tuple_dir libcudacxx/include/cuda/std/__conceptsRepository: NVIDIA/cccl
Length of output: 31007
🏁 Script executed:
#!/bin/bash
set -eu
sed -n '365,395p' libcudacxx/include/cuda/std/__concepts/concept_macros.h
sed -n '1,90p' libcudacxx/include/cuda/std/__tuple_dir/tuple_size.h
sed -n '1,78p' libcudacxx/include/cuda/std/__tuple_dir/tuple_like.h
git diff -- libcudacxx/include/cuda/std/__tuple_dir/tuple_like.hRepository: NVIDIA/cccl
Length of output: 7520
🏁 Script executed:
#!/bin/bash
set -eu
sed -n '210,295p' libcudacxx/include/cuda/std/__concepts/concept_macros.h
command -v g++ || true
command -v clang++ || true
python3 - <<'PY'
from pathlib import Path
p = Path("libcudacxx/include/cuda/std/__concepts/concept_macros.h")
text = p.read_text()
for name in ("_CCCL_CONCEPT_REQUIREMENT_CASE__CCCL_SWITCH_REQUIRES",
"_CCCL_CONCEPT_REQUIREMENT_0",
"_CCCL_CONCEPT_REQUIREMENT_1"):
print(name, text.find(name))
PY
cat >/tmp/tuple_size_probe.cpp <<'CPP'
`#include` <type_traits>
template<class> struct tuple_size;
template<class T> inline constexpr int tuple_size_v = tuple_size<T>::value;
template<class T>
concept member_form = requires {
requires (std::is_same_v<T, int>);
requires (tuple_size<T>::value == 2);
};
template<class T>
concept variable_form = requires {
requires (std::is_same_v<T, int>);
requires (tuple_size_v<T> == 2);
};
static_assert(!member_form<int>);
static_assert(!variable_form<int>);
CPP
if command -v g++ >/dev/null 2>&1; then
g++ -std=c++20 -fsyntax-only /tmp/tuple_size_probe.cpp
fi
if command -v clang++ >/dev/null 2>&1; then
clang++ -std=c++20 -fsyntax-only /tmp/tuple_size_probe.cpp
fiRepository: NVIDIA/cccl
Length of output: 5471
🏁 Script executed:
#!/bin/bash
set -u
cat >/tmp/cccl_fallback_probe.cpp <<'CPP'
template<bool>
struct select {};
template<>
struct select<true> {
template<class T>
using type = T;
};
template<bool B, class T = void>
using enable_if_t = typename select<B>::template type<T>;
template<class> struct tuple_size;
template<class T>
inline constexpr int tuple_size_v = tuple_size<T>::value;
template<bool B, enable_if_t<B, int> = 0>
inline constexpr int requires_value = 0;
template<class T>
inline constexpr bool tuple_like = false;
template<class T>
struct member_form {
template<class U>
static auto check()
-> enable_if_t<
(decltype(requires_value<tuple_like<U>>{}),
decltype(requires_value<(tuple_size<U>::value == 2)>{}),
true),
void>;
};
template<class T>
struct variable_form {
template<class U>
static auto check()
-> enable_if_t<
(decltype(requires_value<tuple_like<U>>{}),
decltype(requires_value<(tuple_size_v<U> == 2)>{}),
true),
void>;
};
template<class T, class = void>
struct has_member : false {};
template<class T>
struct has_member<T, decltype(member_form<T>::template check<T>())> : true {};
template<class T, class = void>
struct has_variable : false {};
template<class T>
struct has_variable<T, decltype(variable_form<T>::template check<T>())> : true {};
static_assert(!has_member<int>::value);
static_assert(!has_variable<int>::value);
CPP
if command -v clang++ >/dev/null 2>&1; then
clang++ -std=c++17 -fsyntax-only /tmp/cccl_fallback_probe.cpp
printf '%s\n' 'clang probe: passed'
else
printf '%s\n' 'clang++ unavailable'
fi
if command -v g++ >/dev/null 2>&1; then
if g++ -std=c++17 -fsyntax-only /tmp/cccl_fallback_probe.cpp; then
printf '%s\n' 'g++ probe: passed'
else
printf '%s\n' 'g++ probe: unavailable or failed'
fi
fiRepository: NVIDIA/cccl
Length of output: 2675
🏁 Script executed:
#!/bin/bash
set -eu
cat >/tmp/cccl_fallback_probe.cpp <<'CPP'
template<bool>
struct select {};
template<>
struct select<true> {
template<class T>
using type = T;
};
template<bool B, class T = void>
using enable_if_t = typename select<B>::template type<T>;
template<class> struct tuple_size;
template<class T>
inline constexpr int tuple_size_v = tuple_size<T>::value;
template<bool B, enable_if_t<B, int> = 0>
inline constexpr int requires_value = 0;
template<class T>
inline constexpr bool tuple_like = false;
template<class T>
struct member_form {
template<class U>
static auto check()
-> decltype(
requires_value<tuple_like<U>>,
requires_value<(tuple_size<U>::value == 2)>,
void());
};
template<class T>
struct variable_form {
template<class U>
static auto check()
-> decltype(
requires_value<tuple_like<U>>,
requires_value<(tuple_size_v<U> == 2)>,
void());
};
template<class T, class = void>
struct has_member { static constexpr bool value = false; };
template<class T>
struct has_member<T, decltype(member_form<T>::template check<T>())> {
static constexpr bool value = true;
};
template<class T, class = void>
struct has_variable { static constexpr bool value = false; };
template<class T>
struct has_variable<T, decltype(variable_form<T>::template check<T>())> {
static constexpr bool value = true;
};
static_assert(!has_member<int>::value);
static_assert(!has_variable<int>::value);
CPP
if command -v clang++ >/dev/null 2>&1; then
clang++ -std=c++17 -fsyntax-only /tmp/cccl_fallback_probe.cpp
printf '%s\n' 'clang probe: passed'
else
printf '%s\n' 'clang++ unavailable'
fi
if command -v g++ >/dev/null 2>&1; then
g++ -std=c++17 -fsyntax-only /tmp/cccl_fallback_probe.cpp
printf '%s\n' 'g++ probe: passed'
else
printf '%s\n' 'g++ unavailable'
fiRepository: NVIDIA/cccl
Length of output: 271
🌐 Web query:
C++ tuple_size_v requires expression hard error variable template substitution NVCC NVRTC
💡 Result:
The issue where std::tuple_size_v causes a compilation error (a hard error) instead of a SFINAE substitution failure arises because the evaluation of the variable template's initializer—std::tuple_size::value—often occurs outside the immediate context of a template substitution [1][2][3]. Under C++ template instantiation rules, SFINAE (Substitution Failure Is Not An Error) only applies to errors occurring within the immediate context of a function signature or template parameter list [2]. When you use std::tuple_size_v, the compiler must instantiate the variable template specialization to determine its value. If the type T is not tuple-like, this instantiation triggers an error in the initializer (std::tuple_size::value). Because this instantiation is considered a side effect of the template substitution rather than an error in the immediate context, the compiler treats it as a hard error [1][2]. In contrast, using std::tuple_size::value directly is often SFINAE-friendly because the failure to find a::value member in the primary template—which is typically undefined—occurs in a context where the compiler can gracefully treat it as a substitution failure [3][4]. For NVCC and NVRTC users, this behavior is a standard C++ language compliance issue rather than a specific toolchain bug [5][3]. When working with CUDA libraries (such as libcu++), encountering this error usually means: 1. The type T passed to tuple_size_v does not meet the requirements of a "tuple-like" type (it lacks an appropriate std::tuple_size specialization) [4]. 2. You are attempting to use it in a SFINAE-constrained context (like a requires clause or std::enable_if) where you expect failure to be silent, but the compiler is forcing an instantiation [2][6][3]. To resolve this, you can: - Use std::tuple_size::value instead of the variable template std::tuple_size_v [5][3]. - If you must use a variable template, wrap it in a custom trait that inherits from std::integral_constant to ensure the failure occurs in a way that respects SFINAE, or define a primary template specialization for your custom types to ensure std::tuple_size::value is always valid [6][4].
Citations:
- 1: https://d-data.ro/c-annotated-march-2022-function-vs-type-serialization-in-c-dwcas-c-modules-in-visual-studio/
- 2: https://www.cppstories.com/2022/sfinea-immediate-context/
- 3: Clang fails to compile when using
std::tuple_size_v<T>in concept, but compiles withstd::tuple_size<T>::valuellvm/llvm-project#125441 - 4: https://cppreference.com/cpp/utility/tuple_size
- 5: https://stackoverflow.com/questions/66214214/different-sfinae-behavior-of-stdtuple-size-v-on-different-compilers
- 6: celtera/avendish@c68baae
important: Preserve the member-based check for non-concepts toolchains. _CCCL_REQUIRES_EXPR places the requirement in a substitution context, but tuple_size_v<remove_cvref_t<_Tp>> can instantiate its initializer outside the immediate context and produce a hard error for non-tuple types. Use tuple_size<remove_cvref_t<_Tp>>::value until NVCC and NVRTC compatibility is established.
Source: Path instructions
⏱️ CCCL compile-time benchmark comparison: Public headers compile-time benchResult: 0 regression row(s), 3 improvement row(s) above threshold.
Artifacts: reports and traces Direct file processing
🟢 Direct file processing — Improvements
|
Description
Convert many instances of
meow<...>::valuetomeow_v<...>.Checklist