C++26: Pack Indexing
sandordargo.com
sandordargo.com
I can totally imagine that. That's double ironic because the syntax is pretty obvious (which I find pretty surprising for a new C++ feature :)
But yeah, it's amazing that we only get this 15 years(!) after the introduction of variadic templates. I can totally see why some languages would decide against ISO standardization.
Sacrificing a couple decades in order to get the syntax just right is worth it. Just look at... Javascript.
This could however be done without introducing angled brackets. myFunction(myFirstClassType); which is what more and more languages nowadays do like Zig.
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p26...
lol how? sed? that's not a "much easier", that's a hack. it's actually much easier to remove `using namespace` because then the compiler will catch resolution errors.
i actually didn't notice this was a header in which ok fine don't use `using namespace` but still this is java EE levels of boiler plate you've got going on;
void SetupInput(const basis::UnitInitializeOptions &options,
basis::core::transport::TransportManager *transport_manager,
basis::core::containers::SubscriberQueueSharedPtr &subscriber_queue,
basis::core::threading::ThreadPool *thread_pool,
const std::unordered_map<std::string, std::string> &templated_topic_to_runtime_topic) {
this signature is 90% namespace resolution - i have to squint to actually find the types... [&]<std::size_t... I>(std::index_sequence<I...>) {
(SetupInput<I>(options, transport_manager, subscriber_queues[I], thread_pool, templated_topic_to_runtime_topic),
...);
}(std::make_index_sequence<INPUT_COUNT>());
would be a lot more readible as for constexpr( size_t I = 0; I < INPUT_COUNT; I++ )
SetupInput<I>(options, transport_manager, subscriber_queues[I], thread_pool, templated_topic_to_runtime_topic);
}
Yes, there's some syntax snags around it (right now I looks mutable, something like `for (constexpr size_t I : INPUT_COUNT)` might be better), but there has to be some sane middleground. const auto [...I] = std::make_index_sequence<INPUT_COUNT>{};
((SetupInput<I>(options, transport_manager, subscriber_queues[I], thread_pool, templated_topic_to_runtime_topic)),...);
yay!I thought the same, but then you lose the ability to control the increment step. For example, one might want to iterate pairwise.
Regarding syntax, you could mandate that the loop variable has to be declared `constexpr` as well, which makes it clear that it can't be modified in the loop body.
Turns out that const-call depth is limited to 512, but by implementation, not by the standard (which is undefined).
And I say that as someone using C++17 at work, not just a smug lisp weenie.
Is a<b, c>(d) a function call or two comparisons combined with the stupidest operator in the language? Impossible to know without type information. (This is also why rust has the super ugly ::<T> for generics, so that it's unambiguous)
auto first(auto... params) { return params...[0]; }
Unless I'm missing something - but the post is showing off the fact that you can index into the list of types of the parameters, as well as the parameters themselves (in which case you need full template syntax).A proper language would have used ... to designate varargs, and a special identifier to hold these args. Just as the macro preprocessor.
But also part of me thinks the people making these complaints don't actually write it (C++). Because if you do then you don't really care (you just pick it up eventually without thinking about it).
Imagine what it could have been if it was designed for programmability from the start.
Circle C++ compiler was designed for that: https://www.circle-lang.org/quickref.html
You have to suck people in with, "hey, you can write these two similar C-like functions under one definition, the correct one of which is automatically deduced and used".
The infamous template error messages are generally a result of two things: first, too many candidate functions because logic is cobbled together out of a nest of SFINAE overloads, which is ameliorated by moving the logic into normal code with if constexpr, etc; and second, type errors occurring deep in the call/expansion stack because unchecked values keep getting passed on just like in a dynamically typed language (which TMP basically is), which is ameliorated by moving the type checks higher up in the stack with concepts or static_assert.
50? That's it!? I work in a code base where a previous developer went nuts with overloads and I routinely get hundreds of lines of output for a single compiler error.
IDE's make this less of a problem.
You can use enable_if and static_assert, alongside type traits to check the types, and give useful error messages.
With C++20 you get concepts lite, which while not being as good as C++0x concepts, still simplify the code a lot, improve error messages, and remove the need for the classical tricks, when used alongside constexpr.
No need to go crazy with them.
C preprocessor macros are a hack, they are useful, but they come with plenty of issues. If you are using macros, there is a good chance there is a superior solution that uses templates.
Abstract classes impact performance, sometimes significantly, and it doesn't solve all problems templates solve. If you don't care, then you would probably be better off doing Java (or languages in the same family) than C++.
If you are not using genericity at all, it may actually be a good thing! Too much abstraction is a common problem. But sometimes you need it. Refusing to use generics will limit what you can do. And if it is your job, it will probably limit your pay too.
At least, as convuluted as C++ may be, template and compile time programming still rely on C++.
But in Rust, you don't need to delve into any kind of macro for polymorphism like you do in C++, since Rust has a real generics system. There is vastly more C++ code that instantiates templates than Rust code that uses macros.
Given that Rust IO and many crate attributes are macro based, not sure who wins out.
The only thing you may complain about are error messages due to duck typing at compile time gone wrong, and even that is kind of already sorted out in C++17.
Anyway, C++ today means C++23.
Naturally checking for speak() existence with enable_if, static_assert and type traits could be added, though this is an example, and nowdays we would make use of concepts anyway.
#include <iostream>
using namespace std;
class Duck {
public:
void speak() const {
cout << "quack";
}
};
class Dog {
public:
void speak() const {
cout << "auau";
}
};
class Cat {
public:
void speak() const {
cout << "miau";
}
};
template<typename T>
void speaking_animal(const T& animal) {
animal.speak();
cout << "\n\n";
}
template<typename... T>
void speaking_farm(const T&... animals) {
auto space_adder = [&](auto creature) -> void {
creature.speak();
cout << " ";
};
(space_adder(animals), ...);
}
int main() {
Duck duck;
Dog dog;
Cat cat;
speaking_animal(duck);
speaking_animal(dog);
speaking_animal(cat);
speaking_farm(duck, dog, cat);
}
Available at https://godbolt.org/z/WWfx5jWfMIt feels like programming in the last five years has turned into a competition of who can make the most abstract meta programming patterns. I think if you find yourself making use of this feature, you’re probably in a deep hole of your own making.
What is an example of a useful function that takes an arbitrary number of arguments each of which has an arbitrary type that isn’t as trivial as the examples given in the article? For super trivial stuff this is useful, and if std used this under the hood to provide std::first_arg or something, that would make sense. But the absence of this language feature doesn’t really seem like it’s holding back 99.9% of users.
Because, how do you use it? How do you add debug printing to try and understand where the bug is? How do you debug even anything?
Like, suppose your concept has a composite requires statement that invokes a constexpr predicate of two derived types, and it is not "true" as you expected, so overload resolution picks the wrong function.
What is the analog of gdb to use in this situation?
C with STL would've saved the world a lot of trouble.
Not the kind of "simplicity" I want. Stay in your reservation, please.