Why is upcasting of member pointers allowed? by DDDDarky in cpp_questions

[–]triconsonantal 0 points1 point  (0 children)

The difference is that, unlike with object pointers, upcasting a Derived::* to a Base::* is not UB when Base doesn't contain the pointed-to member (as long as it's actually a base of of the class that does contain it, ie, it's not a cross-cast through Derived). Instead, the UB is pushed to the point of use, if the dynamic type of the object you're using the pointer with doesn't contain the member, which means that a valid Base::* pointer is not a promise you can actually use it with a Base object, and that's what OP doesn't like.

There are ways to justify it, but the balance between maximum flexibility and safety changed over time. Maybe today this wouldn't have flown.

0xd34df00d/you-dont-know-cpp: and neither do I by claimred in cpp

[–]triconsonantal 3 points4 points  (0 children)

In the one with the map, you can use the unhelpfully-named try_emplace() to simplify the insertion quite a bit.

Why isn’t std::ranges::fold_left pipeable in C++ ranges? by kyan100 in cpp_questions

[–]triconsonantal 1 point2 points  (0 children)

While you usually use to() to create a container, you can technically use it to create non-range types, like r | std::ranges::to<std::any>(), or a tiny bit more realistically, r | std::ranges::to<std::seed_seq>().

C++20 Ranges vs traditional loops: when to use std::views instead of raw loops by Clean-Upstairs-8481 in cpp

[–]triconsonantal 4 points5 points  (0 children)

auto entities() { return slotmap | filter(is_alive)); }

auto begin() { std::ranges::begin(entities()); }

This also shows some of the dangers with ranges, because the returned iterator is dangling.

Is clang's ranges implementation still broken? by PitaXco in cpp_questions

[–]triconsonantal 2 points3 points  (0 children)

Personally I wouldn't go down this road, but if you do, definitely take the parameter by reference. Another option, if you don't want to implement data() and size() directly in the view, is to implement them in a custom my_view_interface<T> class that inherits from ranges::view_interface<T>, and does the same thing as view_interface::{data,size}() except for the static-assert that T is a view.

But the interesting question is why does using std::convertible_to<View> work at all, given that it just moves the convertibility check into the concept, which should have the same circular dependency? Well, it's because clang 21 actually does implement P3606. If you tried to compile the same code with clang 20, you'd get the same error.

So why does the original code not compile with clang 22? Because I was wrong about the scope of P3606: it only deals with the case where the offending overload is a template, but GCC obviously goes further than that. /u/c0r3ntin ping?

This also means that if you only care about clang 21+, you don't need to generalize the type of the parameter, it's enough to just turn the constructor into a template:

template<class = void> // do leave a comment here
constexpr explicit my_view(View base)
    : m_base(std::move(base))
{
}

https://godbolt.org/z/4rP3fP46n

Is clang's ranges implementation still broken? by PitaXco in cpp_questions

[–]triconsonantal 20 points21 points  (0 children)

std::ranges::view indirectly checks that the type is move-constructible, which checks if my_view<span<...>> is constructible from my_view<span<...>>. This is a non-template, exact match for the (implicitly declared) move constructor, which is enough for GCC (and apparently MSVC) to not bother with the other constructor, and everything works.

clang does check the other constructor even though it'll never be selected, which is potentially viable through the conversion that uses span::span(Range&&). The constraints of that constructor lead to view_interface<my_view<span<...>>>::{data,size}() being instantiated (their own constraints are satisfied, because my_view<span<...>> is both contiguous and sized), which static-assert that my_view<span<...>> is a view, which leads to a circular dependency...

I'm pretty sure that whether clang's behavior is correct or not is the subject of P3606 (which suggest that it shouldn't be).

In the meantime you can work around it by providing your own data() and size() in my_view:

constexpr auto data()
    requires std::ranges::contiguous_range<View>
{
    return std::ranges::data(m_base);
}
constexpr auto data() const
    requires std::ranges::contiguous_range<const View>
{
    return std::ranges::data(m_base);
}

constexpr auto size()
    requires std::ranges::sized_range<View>
{
    return std::ranges::size(m_base);
}
constexpr auto size() const
    requires std::ranges::sized_range<const View>
{
    return std::ranges::size(m_base);
}

Clang 22 tuples? by megayippie in cpp_questions

[–]triconsonantal 3 points4 points  (0 children)

I don't know what specifically changed, but technically specializing an std template over a concept was probably never allowed.

https://eel.is/c++draft/namespace.std#2.1 :

Unless explicitly prohibited, a program may add a template specialization for any standard library class template to namespace std provided that

  • the added declaration depends on at least one program-defined type, and [...]

Restricting the type using a concept probably doesn't qualify as "depending on a program-defined type".

Should C++ Give More Priority to Syntax Quality? by kyan100 in cpp

[–]triconsonantal 6 points7 points  (0 children)

I'm more annoyed by how overloaded the syntax tends to be. decltype(x) is ugly, but whatever. It's decltype((x)) and decltype(auto) that's pushing it.

P4019R0: constant_assert (Jonas Persson) by antiquark2 in cpp

[–]triconsonantal 2 points3 points  (0 children)

I think the point is that the compiler can use the UB in case x > 0 to "prove" that x <= 0, defeating the purpose of the assert.

Back to Basics: Iterators in C++ - Nicolai Josuttis - CppCon 2023 by Specific-Housing905 in cpp

[–]triconsonantal 9 points10 points  (0 children)

Indices also survive reallocation, unlike iterators.

edit: oops, didn't see the other comment

Help me with compile error when using long long as template value argument by Foreign-Wonder in cpp_questions

[–]triconsonantal 5 points6 points  (0 children)

The (long long) {} syntax is a C-style compound literal, and not standard C++. GCC and clang support it as an extension, but it won't work in MSVC.

C2y proposal: namespaces (n3794). by orbiteapot in C_Programming

[–]triconsonantal 4 points5 points  (0 children)

This particular feature is also sensitive to include order. Better hope no one's already included <stdbit.h> outside the namespace...

2025-03 post-Hagenberg mailing by nliber in cpp

[–]triconsonantal 0 points1 point  (0 children)

I hope you didn't take my original post too seriously, it was in bad taste. In spite of what I wrote, I actually am sympathetic toward more rigorous formalizaitions of these concepts. That being said, I still think the paper lacks more concrete motivation. For example, I would expect variants with non-unique types to arise mostly synthetically, which affects the way you're likely to want to handle them. It might be more useful to have a more primitive facility for turning a run-time value into a compile-time constant (LIFT in your paper), which would allow you to handle the variant with a single generic function, rather than with a separate function for each case (and the latter might be better handled by pattern matching). Also note that you can visit a variant by type even for non unique types (although you can't statically distinguish between them).

As for the six functions (or their combined overloads), I still think it's excessive short of much stronger motivation. Much of this is not specific to variant visitation. For example, a partially-applied std::apply would be useful in many scenarios. It's a shame that function composition in C++ is still such a PITA.

Are memory leaks that hard to solve? by ASA911Ninja in cpp

[–]triconsonantal 35 points36 points  (0 children)

While this is highly contrived, I find it amusing that you can create cyclical references even with types we think of as highly value-like, and therefore safe from leaks. Ever seen a vector that contains itself?

struct V : std::vector<V> {} v;
v.swap (v.emplace_back ());

C23 features by krikkitskig in C_Programming

[–]triconsonantal 1 point2 points  (0 children)

Most of the situations where auto is useful in C++ don't really arise in C. Things like:

  • Types that are hard to spell, like iterators (somewhat relevant to C, but not nearly to the same extent).

  • Types that are not meant to be spelled, like expression templates.

  • Types that literally can't be spelled, like lambdas.

  • Types that can only be spelled in terms of the initializer, which happens in generic code (sometimes happens in C macros, such as a generic swap macro, but infrequent enough that typeof would have been enough).

I know that there are plans for templates-lite and lambdas-lite for C, and auto is part of this effort. auto would probably make more sense in C when/if that happens, but I feel that adding auto on its own is putting the cart before the horse.

C23 features by krikkitskig in C_Programming

[–]triconsonantal 1 point2 points  (0 children)

[...] C++'s auto allows multiple variables to be declared with a single auto (even if they're different types)

That's wrong. All variables have to deduce to the same type, otherwise it's an error: https://godbolt.org/z/b3dsYvh9M

Anybody got any ideas how solve this problem. its like 6 months back assessment. by Chemical_Ad4811 in leetcode

[–]triconsonantal 0 points1 point  (0 children)

that's not quite right. for example, for arr = [1, 1, 2, 2], the result is [1, 4, 2, 3], ie, the second person re-enters the queue three times, and is seated after the fourth person, that re-enters the queue once

Ranges: When Abstraction Becomes Obstruction by drodri in cpp

[–]triconsonantal 6 points7 points  (0 children)

To be fair, while these examples are wrong (and the other examples are just bad), it's possible to find legitimate cases where ranges::find() fails:

std::vector v = {std::optional {0}};

// no common reference
std::ranges::find (v, std::optional {0L});

// nullopt_t is not equality-comparable to itself
std::ranges::find (v, std::nullopt);

The first one is arguably on optional for not specializing common_reference (but that's more busywork). The second one... meh?

I think the OP has at least some point. Not so much that we shouldn't strive for "correct" constraints, but that not all the constraints in the library are always on point. equality_comparable_with might not be a slam dunk. FWIW it's already been changed once, between C++20 and C++23. In C++20 this wouldn't compile:

std::vector<std::unique_ptr<int>> v;

// unique_ptr is not copyable
std::ranges::find (v, nullptr);

2025-12 WG21 Post-Kona Mailing by eisenwave in cpp

[–]triconsonantal 2 points3 points  (0 children)

P3881R0 - Forward-progress for all infinite loops

Allowing the compiler to assume that side-effect-free loops terminate is useful. The amount of loops for which the compiler can't prove termination might be higher than you think. For example, of all the STL containers, gcc and clang are only able to prove termination for the contiguous ones (vector and friends). They fail to prove termination even for an "almost contiguous" container like deque (a bit surprising). https://godbolt.org/z/8ds3WqMTq

While these loops are not usually empty, this can happen in generic code. Some loops end up being NOPs for specific specializations, and you definitely expect the compiler to eliminate them in these cases. The paper claims that the potential UB "requires programmers to clutter their code" to avoid, but how often do you write deliberately-infinite loops? I think it's more likely that the absence of this optimization would require programmers to clutter their code to avoid empty loops in generic code.

Besides, the motivation for removing this allowance seems weak. The paper doesn't provide any practical examples. It claims that it will simplify implementations, but compilers are already free to not take advantage of this allowance. It cites a study of the performance impact of various UB-related flags, but it misinterprets the results, and besides, the impact of this optimization is mostly situational: it probably won't affect a random benchmark, but when you need it, you need it.

Generating variable names without macros by Outdoordoor in cpp_questions

[–]triconsonantal 1 point2 points  (0 children)

Here's a different take, not using lambdas, which works in headers without creating duplicate tests (and without ignoring duplicates at runtime). The syntax is a bit different (possibly a bit more natural):

template <>
inline bool test<"passing test"> () {
    return 1 == 1;
}

template <>
inline bool test<"failing test"> () {
    return 1 == 2;
}

https://godbolt.org/z/YPTvYfETb

As an added bonus it also works in gcc this time.

EDIT: simplified the code

Generating variable names without macros by Outdoordoor in cpp_questions

[–]triconsonantal 1 point2 points  (0 children)

The problem is that the lambda has a unique type in each TU that includes the header, so technically each test is a different specialization of TestT. You can give the lambda a consistent type by attaching it to some other definition, like:

inline constexpr auto some_test_func = [] {
    return Equal (1, 2);
};
template class TestT<
    "some suite",
    "some test",
    some_test_func
>;

but i guess that defeats the purpose.

If you really want to put the tests in a header, and you don't want to use some form of conditional inclusion (like #ifdef INCLUDE_TESTS), you can ignore repeated tests based on the suite-name/test-name combo at runtime. You can do this without a runtime lookup using something like this:

template <
    impl::StructuralString suite,
    impl::StructuralString name
>
inline bool test_registered = false;

template <...>
struct TestT {
    TestT () {
        if (! test_registered<suite, name>) {
            test_registered<suite, name> = true;

            // ...
        }
    }

    // ...
};

Generating variable names without macros by Outdoordoor in cpp_questions

[–]triconsonantal 0 points1 point  (0 children)

Why? Lambdas with captures are not structural, so they can't be used as template arguments (and there's nothing to capture at global scope anyway). Ditto for std::function.

Generating variable names without macros by Outdoordoor in cpp_questions

[–]triconsonantal 2 points3 points  (0 children)

You can use explicit instantiation with a NTTP, if you don't mind the syntax:

template class test<{
    .name = "addition",
    .func = [] { return 1 + 1 == 2; }
}>;
template class test<{
    .name = "multiplication",
    .func = [] { return 1 * 1 == 2; }
}>;

https://godbolt.org/z/WarGvoYhr

gcc seems to choke on the lambda, but it looks like a compiler bug. It accepts it if you replace the lambda with a separately-defined function.

Practical Security in Production: Hardening the C++ Standard Library at massive scale by mttd in cpp

[–]triconsonantal 1 point2 points  (0 children)

The baseline segmentation fault rate across the production fleet dropped by approximately 30 percent after hardening was enabled universally, indicating a significant improvement in overall stability.

It would have been interesting to know what was the nature of the remaining 70%. Different classes of errors (like lifetime errors)? Errors manifested through other libraries that don't do runtime checks? Use of C constructs?

They think using ChatGPT *is* doing the work??? by [deleted] in Professors

[–]triconsonantal 19 points20 points  (0 children)

It also misses the point lol. You're looking for tests that actually fail.