|
Xerophyte posted:Not sure I understand what the problem is. If you want The problem was that the functions took two different types. Absurd Alhazred posted:Well, you could use std::is_integral<T>::value. It's a constexpr so if statements with it are handled at compile time, I think. Wouldn't work this will have to branch out to several options. You just run into the same problem as before.
|
# ? Jul 20, 2020 20:47 |
|
|
# ? Apr 29, 2024 16:26 |
|
rjmccall posted:If your problem is that the code on one of the paths doesn't actually compile when the type is int or whatever, that's exactly the use case of C++17's constexpr if. Now that seems like a much better option. Xeom fucked around with this message at 20:55 on Jul 20, 2020 |
# ? Jul 20, 2020 20:48 |
|
Hey so I don't have a much experience with proper C++ Exception handling, but its seems like its Really Bad? My problem is I want to throw from some class operators when they are given bad operands, and catch it at a higher level where I can provide better context in a message to the user. But as far as I understand from some quick searches, there's no way to verify at compile time that exceptions would be handled for a given function/operator? I mean, I can temporarily delete my operators definitions and try to compile, which would kinda help me find all the places they are used in code, then make sure the proper try/catch are in place, but is there really no way to protect in the future when someone else who doesn't know about these exceptions goes and adds more calls to these operators?
|
# ? Jul 27, 2020 21:00 |
|
Congratulations, you have discovered why exceptions are a terrible design idea and should essentially never be used! This isn't really a C++ thing, exceptions are bad in all languages. Return errors and have explicit visible logic instead of using exceptions to do nonlocal jumps.
|
# ? Jul 27, 2020 21:29 |
|
Foxfire_ posted:Congratulations, you have discovered why exceptions are a terrible design idea and should essentially never be used! This isn't really a C++ thing, exceptions are bad in all languages. Works great as long as you never have to deal with hardware.
|
# ? Jul 27, 2020 21:52 |
|
peepsalot posted:Hey so I don't have a much experience with proper C++ Exception handling, but its seems like its Really Bad? that dude going on about exceptions being evil is onto something, but i would also avoid operator overloading precisely because it might save typing but can produce headaches like the above.
|
# ? Jul 28, 2020 00:20 |
|
Absurd Alhazred posted:Works great as long as you never have to deal with hardware. Not sure what you mean by this? Hardware interrupts/exceptions are a completely separate concept from language level exception throwing. No one uses C++ exceptions in embedded or kernel code.
|
# ? Jul 28, 2020 04:06 |
|
Bruegels Fuckbooks posted:that dude going on about exceptions being evil is onto something, but i would also avoid operator overloading precisely because it might save typing but can produce headaches like the above. eh both are fine, just have a really good reason
|
# ? Jul 28, 2020 04:08 |
|
Foxfire_ posted:Congratulations, you have discovered why exceptions are a terrible design idea and should essentially never be used! This isn't really a C++ thing, exceptions are bad in all languages. At least the Java thing where you have to be much more explicit about them is differently bad.
|
# ? Jul 28, 2020 17:46 |
|
OK, I think I figured out a reasonable solution. Short answer: Instead of throwing, I'm gonna use something kinda similar to Andrei Alexandrescu's Expected<T>. Long answer: This relates to the same project that my questions itt are usually in regards to: a DSL interpreter, where Values are represented internally with a boost::variant. The issue here was that undefined operations (usually from mixing incompatible types in some expression) were returning an "undef" type which just made things harder to debug without any clear warnings or error messages about which piece of script caused the undef. The Value type has various operators defined using boost::static_visitors, and is sort of the lowest level code, which is separate from the AST, such that it has no knowledge of source line location information. Since Value is already a variant, I didn't want to wrap it in another layer of Expected<T>... "undef" was previously represented with boost::blank, but I realized that its essentially the "unexpected" type, so it probably makes more sense for it to be an object which requires a message string, indicating some reason it got set to undef. That way higher level code with access to AST info can deal with undefined return values by spitting out useful messages, and appending source file, line number info, etc.
|
# ? Jul 28, 2020 18:11 |
|
Is there a general stigma against using namespace std; or similar at global scope within a source file? None of the places I've worked have had an issue with it, but I've seen it mentioned as a bad thing and now I'm wondering. (Obviously header files are a different story, so I'm specifically asking about source files.)
|
# ? Aug 11, 2020 16:30 |
Yes, importing an entire namespace wholesale, especially std, is an easy way to get all kinds of global symbols you didn't expect. The entire point of namespaces is to isolate symbols and avoid collisions.
|
|
# ? Aug 11, 2020 16:49 |
|
ultrafilter posted:Is there a general stigma against using namespace std; or similar at global scope within a source file? None of the places I've worked have had an issue with it, but I've seen it mentioned as a bad thing and now I'm wondering. Short answer: yes. In part to avoid spurious identifier collisions, in part to avoid programmer confusion. Long answer: The rule is really to avoid using namespace foo for any namespace, since doing so always risks triggering some collision if the foo library updates its namespace with some new identifier. std just suffers especially since its functions and types are very often reimplemented in different libraries that use the same names, so it's more likely than most to cause collision issues. The general advice is to try to be specific about what identifiers you're importing. Avoid importing entire namespaces, and avoid importing over large scopes. Importing the entirety of a large namespace, like std, for a large scope, such as an entire cpp file, is code smell to a lot of people. Doing things like using clock = std::chrono::high_resolution_clock in local scopes and for specific classes that use the date/time library is great. Finally, something like plain vector<float> xs is ambiguous since you cannot immediately tell what vector is meant. Readers will need to track down the namespace import to understand the code, which is likewise harder if the import is general, for a large scope and far away from the declaration. std::vector<float> xs is immediately obvious. It matters a lot what the local shop style is too of course. If everyone where you work is used to using namespace std being standard then changing it might be more confusing.
|
# ? Aug 11, 2020 17:07 |
|
Also often what you really want is using namespace::thing, rather than the whole namespace.
|
# ? Aug 11, 2020 18:12 |
|
Xarn posted:Also often what you really want is using namespace::thing, rather than the whole namespace. Yeah. If the standard library had been designed with nested namespaces to start, doing using namespace std::io; or similar would probably be fine, but std as it is is way too big.
|
# ? Aug 11, 2020 18:16 |
|
ultrafilter posted:Is there a general stigma against using namespace std; or similar at global scope within a source file? None of the places I've worked have had an issue with it, but I've seen it mentioned as a bad thing and now I'm wondering. If you're working on a project where you have to include all sorts of header files like windows.h, using namespace std (even in the cpp files) will usually just lead to stuff not compiling because of namespace clashes, and that's the best possibility you can hope for. The worst outcome is that stuff compiles but something with the same name but different behavior but not different enough was defined in both poo poo.h and std, and it causes hard-to-troubleshoot unforeseen issues.
|
# ? Aug 11, 2020 23:58 |
|
I meanC++ code:
|
# ? Aug 12, 2020 00:23 |
|
As others have mentioned using namespace std can cause actual problems but even if it didn’t it still shouldn’t be used. Why not? Because explicit is better than implicit. Who among us really knows the standard library? Even a moment’s confusion about where a function comes from is not worth the timed saved typing std::. And the confusion often lasts more than just a moment. Some people act like having to type std:: is an awful burden. Those people should be cast out. The exception to this is when using the chrono_literals which to my knowledge can’t be used without using namespace (this is a crime). For other namespaces like the verbose, nested boost ones, alias the namespace to something brief. For example boost::filesystem gets aliased to fs. Using statements in a translation unit are fine for bringing in a single symbol like a class or a function. This is sufficiently explicit.
|
# ? Aug 12, 2020 01:37 |
|
Xerophyte posted:It's difficult for code to touch windows.h and remain free of horror regardless of namespace practices, really.
|
# ? Aug 12, 2020 16:29 |
|
If you're developing on Windows you're going to have a bad time.
|
# ? Aug 12, 2020 16:32 |
|
ultrafilter posted:If you're developing you're going to have a bad time.
|
# ? Aug 12, 2020 17:43 |
|
have you tried developing... on weed??
|
# ? Aug 12, 2020 18:27 |
|
I do all my deving on weed. I'm trying to make an iterator for a data structure that has two different arrays whose data I would like the user to have access to when using a ranged based for loop. Right now my implementation is really ugly, I'm returning a Pair<type1&, type2&>, but this isn't an lvalue and generally makes things ugly when used in a ranged based for loop. Is there a better approach?
|
# ? Aug 13, 2020 19:58 |
|
Xeom posted:I do all my deving on weed.
|
# ? Aug 13, 2020 22:59 |
|
peepsalot posted:If the arrays are a 1:1 match, then it probably would make most sense to merge them into a single array of structs containing those two data members. This will give better data locality for cache performance etc., and you can return a reference and/or const reference to the struct from your iterator operator*(). That's what I was trying to avoid because in most operations I'm interested in only one array, and it would be a lot faster to keep them separate as a struct of arrays. However that's probably the best choice if I wanna do this. That or go just use lambda functions to modify things.
|
# ? Aug 13, 2020 23:53 |
|
Do you actually care about the difference in performance?
|
# ? Aug 13, 2020 23:55 |
|
If they aren't actually adjacent in memory, a client will always be able to figure that out. If you don't want to move them, return some adapter that has the operators you need and internally translates the accesses to the appropriate locations. code:
|
# ? Aug 14, 2020 00:21 |
|
ultrafilter posted:Do you actually care about the difference in performance? Probably not, but I figured I'd ask.
|
# ? Aug 14, 2020 00:46 |
|
Can I make this work?code:
And visual studio produces this: calling the default constructor for "ButtonMapping" does not produce a constant value Where ButtonMapping is this. It has a constructor that is old code that I can't easily get rid of. If I try this with a class with no constructors, then it works. What is it about the existence of the constructor that breaks this? This is something that has always confused me. Adding a constructor to a class seems to remove some of the default behavior. How can I add a constructor to a class without magical things happening behind the scenes? code:
|
# ? Aug 28, 2020 17:50 |
|
Your constructor is not constexpr and I believe that code should compile if you just change the constructor to constexpr ButtonMapping( ... ). That requirement exists because in general a constructor may have arbitrary side-effects and cannot be invoked at compile time. The aggregate initialization for a struct with no user-declared constructor is constexpr, which is why it works without the constructor. In general, you can only declare constexpr variables of types that meet the requirement of LiteralType.
|
# ? Aug 28, 2020 19:08 |
|
After trying getting into C++ multiple times before I recently started reading The Design and Evolution of C++ (1994) and I'm having great time just messing with the language. C++98 feels lot more like an extension to my beloved C instead of a horrid mess of templates and incomprehensible standardese (which I assume I'll learn to appreciate once I understand its motivations).code:
e: im the friend declaration of D 👀 ee: drunkem typos matti fucked around with this message at 19:25 on Aug 31, 2020 |
# ? Aug 31, 2020 17:20 |
|
The more I see the more I'm convinced that multiple inheritance is almost always a mistake.
|
# ? Aug 31, 2020 17:30 |
|
ultrafilter posted:The more I see the more I'm convinced that multiple inheritance is almost always a mistake. Multiple implementation inheritance is always a mistake. Multiple interface inheritance is cool and good.
|
# ? Aug 31, 2020 17:53 |
|
Zopotantor posted:Multiple implementation inheritance is always a mistake. Multiple interface inheritance is cool and good. Interface + epsilon implementation can work fine, IMHO --- i.e. interface + helper methods, since you don't want your virtuals to be non-private, do you?
|
# ? Aug 31, 2020 18:01 |
|
ultrafilter posted:The more I see the more I'm convinced that multiple inheritance is almost always a mistake. I'm sure there are valid use cases for it, but multiple implementation inheritance is one of those language features where a) Someone thinks they are smarter than they are and uses it to solve a problem. b) They produce something that seems like it works. c) There is some sort of hosed up side-effect related to object initialization / copying the object / resource de-allocation. d) It takes a while to fix the problem. e) It wasn't really necessary to use the feature in the first place. I also find that the more it's used, the harder it is to get my head around the classes involved - it can be like goto on steroids. The classes look much nicer but are just harder to reason about.
|
# ? Sep 1, 2020 22:51 |
|
mixins are so nice, though
|
# ? Sep 1, 2020 23:08 |
|
Multiple implementation inheritance can maybe be OK if the class hierarchies involved are completely orthogonal. Early in my career I worked on a multiplatform graphics engine that allowed us to design forms for a desktop application. We had one set of classes that represented the abstract logic for various controls, and another that handled everything OS-specific. The only issues with that were related to the inheritance hierarchy being deep and C++ not having a mechanism to require every class deriving from a given parent to supply its own implementation of some pure virtual function (hello object slicing!). We probably still should've used composition, though.
|
# ? Sep 1, 2020 23:20 |
|
Multiple interface inheritance is usually a bad idea; if your interface is really that complicated, consider having a separate table of traits that you can extract statically or dynamically from the complete type.
|
# ? Sep 2, 2020 00:51 |
|
rjmccall posted:Multiple interface inheritance is usually a bad idea; if your interface is really that complicated, consider having a separate table of traits that you can extract statically or dynamically from the complete type. Why do you think that "multiple interface inheritance" implies a complicated interface? Since interfaces just define behaviours, a description of actions, I cannot really see how can one become complicated. The implementation may be, but it's definitely not a given. It doesn't have to be. But I may be missing something here.
|
# ? Sep 2, 2020 04:33 |
|
|
# ? Apr 29, 2024 16:26 |
|
Multiple interface inheritance means that there are multiple unrelated abstract interfaces being satisfied by a single object. That is already complicated.
|
# ? Sep 2, 2020 04:54 |