Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today

Illusive gently caress Man posted:

oh duh yeah that should work. I've never needed to use a deleter before so I forgot it was a thing

edit: either I don't understand how to use deleters, or this doesn't work. Can't convert unique_ptr<abcd, MyNoOpDelete> to unique_ptr<abcd, std::default_delete<abcd>>

I'd just use a unique_ptr<reference_wrapper<T>> so they're explicitly owning a reference rather than some weird fake unique_ptr. Of course, you'd better be really certain that the references don't end up dangling.

Adbot
ADBOT LOVES YOU

eth0.n
Jun 1, 2012

Ralith posted:

I'd just use a unique_ptr<reference_wrapper<T>> so they're explicitly owning a reference rather than some weird fake unique_ptr. Of course, you'd better be really certain that the references don't end up dangling.

If the class operates on the unique_ptr using the arrow operator, which seems likely, this won't work.

I think it's more likely that unique_ptr<shared_ptr<T>> would work, since the arrow operator will automatically pass all the way down.

For example:

code:
unique_ptr<foo> pfoo = ...;
unique_ptr<reference_wrapper<foo>> rfoo = ...;
unique_ptr<shared_ptr<foo>> sfoo = ...;

pfoo->bar(); //works
rfoo->bar(); //doesn't work
sfoo->bar(); //works
noop deleter is probably the best of all these bad options, though. No good options when dealing with such a fundamental design flaw...

Edit: except, isn't the deleter type part of the static type of a unique_ptr? So if the classes can't be changed, is noop deleter actually possible?

eth0.n fucked around with this message at 22:05 on Jun 2, 2016

Sex Bumbo
Aug 14, 2004

eth0.n posted:

Edit: except, isn't the deleter type part of the static type of a unique_ptr? So if the classes can't be changed, is noop deleter actually possible?

You could make an interface that accepts a unique_ptr with a deleter but yeah it's probably the case that everything's gonna be a pain. If the implementation is built to always call delete on something and subsequently free a bunch of heap memory, there's no option but to heap allocate some nonsense memory for it.

That is, if the free is in the implementation and can't be changed, you might as well be trying to trying to share memory that you call free on.

Illusive Fuck Man
Jul 5, 2004
RIP John McCain feel better xoxo 💋 🙏
Taco Defender
I'm just going to ask the authors of the class to let me add a constructor that takes a raw pointer without ownership.

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today

eth0.n posted:

If the class operates on the unique_ptr using the arrow operator, which seems likely, this won't work.

I think it's more likely that unique_ptr<shared_ptr<T>> would work, since the arrow operator will automatically pass all the way down.

For example:

code:
unique_ptr<foo> pfoo = ...;
unique_ptr<reference_wrapper<foo>> rfoo = ...;
unique_ptr<shared_ptr<foo>> sfoo = ...;

pfoo->bar(); //works
rfoo->bar(); //doesn't work
sfoo->bar(); //works
noop deleter is probably the best of all these bad options, though. No good options when dealing with such a fundamental design flaw...

Edit: except, isn't the deleter type part of the static type of a unique_ptr? So if the classes can't be changed, is noop deleter actually possible?

I mean, it'd be trivial to write reference_wrapper but implementing the interface required, at which point the trivial destructor behaves like the noop deleter idea except without breaking the API.

Doc Block
Apr 15, 2003
Fun Shoe

leper khan posted:

Because the GPL is a legal virus that you may not want your code infected with? You can't just copy pasta code like that without thought.

Yes, I'm aware of that, which is why I said if his application was going to be licensed under the GPL or LGPL. He mentioned right there in his first post that he was going to make his application open source.

Now that he's said he wants to license it under MIT then yeah, obviously, he can't just copy/paste the files without serious legal consideration.

ExcessBLarg!
Sep 1, 2001

Sagacity posted:

Hmm, I'm planning to license the code under MIT but I'd like the application itself to also fall under MIT.
You can license all the non-KDE code under MIT. While the whole application must still be distributed under the LGPL at least folks can take the non-KDE portions of the code for use in other projects with fewer license concerns.

Sagacity posted:

I'd then have to provide a separate project with the copy/pasted code that generates a .dll/.so with the KDE stuff I can link my application with. So it'd still be a copy/paste but the LGPL would be restricted to that separate project
I don't think it has to be a separate "project" (however you define that term). For example, you can in the same source repository have an application directory that's licensed however, and a library directory that's LGPL so long as you comply with the terms of the LGPL with regard to distribution of the library directory and the application as a whole permits linking with modified library directory contents. This is basically the same as the first option except you're using a stricter separation of the application and library code to facilitate the linking requirements of the LGPL with LGPL-incompatibly licensed code.

The concern with shipping application and (L)GPL code together is whether either portion is really a derived work of the other, such as if the "library" code was heavily modified to support just that application. I think it's pretty defensible to ship a portion of KDE libraries as a convenience to having to ship and build the whole thing, especially if the application can be alternatively built with the full KDE frameworks library instead of the stub.

Sagacity posted:

Or, alternatively, just build the KDE frameworks myself and redistribute the binaries under the proviso that I don't change them so anyone could in theory compile the libs for themselves
You're still obligated to provide the source for the LGPL binaries here.

Sagacity posted:

Or, final option, just use a "find_package KF5" in my CMakeLists.txt along with some build instructions
If you don't ship LGPL binaries you don't have to ship the source. This is the cleanest from a licensing-distribution perspective, but requires the user to locate and install a fairly hefty library for two classes.

Sagacity
May 2, 2003
Hopefully my epitaph will be funnier than my custom title.

ExcessBLarg! posted:

Tons of really useful stuff
Thanks! That's pretty clear. I'll have to see what I'm going to do, I'm not too fussed about having to license my application as LGPL if I really need to. I guess the whole point of LGPL is precisely this: Making sure others also start using LGPL for their derived works :)

ExcessBLarg! posted:

You're still obligated to provide the source for the LGPL binaries here.
Even if the LGPL binaries would then only be the actual KDE binaries? The rest of the binaries would be my (MIT) application that only links to a couple of unmodified KDE binaries. I'd basically just use the KItemModels.dll/.so and KItemViews.dll/.so that is generated when you'd build KDE yourself.

Sagacity fucked around with this message at 16:11 on Jun 3, 2016

Private Speech
Mar 30, 2011

I HAVE EVEN MORE WORTHLESS BEANIE BABIES IN MY COLLECTION THAN I HAVE WORTHLESS POSTS IN THE BEANIE BABY THREAD YET I STILL HAVE THE TEMERITY TO CRITICIZE OTHERS' COLLECTIONS

IF YOU SEE ME TALKING ABOUT BEANIE BABIES, PLEASE TELL ME TO

EAT. SHIT.


ExcessBLarg! posted:

The concern with shipping application and (L)GPL code together is whether either portion is really a derived work of the other, such as if the "library" code was heavily modified to support just that application. I think it's pretty defensible to ship a portion of KDE libraries as a convenience to having to ship and build the whole thing, especially if the application can be alternatively built with the full KDE frameworks library instead of the stub.

This is really the important bit, modifying LGPL libraries to support your specific use case is on legally very shaky ground (i.e. you might then have to license your application under LGPL because it's derived work). Even if they are done as separate projects.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
This month's proposal mailing includes a comprehensive guide and rational for the static reflection proposal: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0385r0.pdf

It's uh, pretty ugly, but it covers all the obvious use-cases for static reflection in a way that I could see plausibly landing in C++.

taqueso
Mar 8, 2004


:911:
:wookie: :thermidor: :wookie:
:dehumanize:

:pirate::hf::tinfoil:

Plorkyeran posted:

It's uh, pretty ugly,
Should fit in perfectly.

Sex Bumbo
Aug 14, 2004
Better than preprocessor bullshit or whatever other ideas people try to pull.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
TTS's proposal this time around is pretty amazing. It never would have occurred to me that passing a field of a tuple as an argument to an overloaded function based on a runtime-provided index was even possible, and it appears to fix all sorts of gross code that I've had to write.

Plorkyeran fucked around with this message at 23:41 on Jun 3, 2016

ExcessBLarg!
Sep 1, 2001

Sagacity posted:

Even if the LGPL binaries would then only be the actual KDE binaries?
Yes, if you distribute (L)GPL binaries you have to either distribute the source alongside it, or make it available (e.g., for download) in the same place.

To comply with the license you can't just distribute precompiled binaries and say "you can download the source here" with a link to KDE's GitHub. The reason is, in part, due to the (L)GPL being drafted before the Internet was commonly accessible and software was still shared or sold on disk or tape. Even in the Internet era, KDE could take their GitHub down or, something, and so it's best to host your own copy. Plus it makes it unambiguous which exact version, branch, tag, etc., of KDE you used to generate the binaries. Also, since we're really just talking about clicking "Fork" on the relevant KDE repos and providing links to your own repos, perhaps with upstream links for convenience, it's not much of a hardship.

I mean, most people won't get bent out of shape if you say "you can download the source here" with an offsite link but the license terms are pretty specific.

Sagacity posted:

I guess the whole point of LGPL is precisely this: Making sure others also start using LGPL for their derived works :)
The GPL has a few purposes, but a big one is to encourage people to write/release free software, instead of defaulting to closed-source software, and to incentivize it by making a library of free software available for their use in doing so. At least, that was the promise when GNU really started becoming big 20 years ago.

Things are generally more complicated now. There's a plethora of competing free software licenses, some of which are mutually compatible and others which are not. The GPL itself even has multiple, popular but incompatible versions. The popularity of social coding and GitHub means that "free" is generally the default, even if actual license terms tend be a bit murky. From a commercial perspective the GPL is a mixed bag. There are many, many vendors that distribute GPLed software that are not in compliance with the license, intentionally or not, and in many cases enforcement is impractical or unlikely. Conversely, companies can comply with the letter of the license by making source dumps available, but without access to revision history and source repositories they're of limited utility.

The reality is that participating in open source is something that one has to value doing, not be compelled to do. For example, Apple and Google do a lot of participation in open source projects, often where licenses (Apache, BSD, MIT, etc.) do not obligate them to, and their participation is much better than riff-raff hardware vendors that post a might-be-the-correct-version of a Linux kernel tarball on their website somewhere. For that reason I think the GPL is outdated in many ways, and personally prefer simpler licenses. I don't have an issue releasing things under the (L)GPL if obligated to, but I generally prefer to stick an MIT license header on any actual source files I write.

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

ExcessBLarg! posted:

To comply with the license you can't just distribute precompiled binaries and say "you can download the source here" with a link to KDE's GitHub. The reason is, in part, due to the (L)GPL being drafted before the Internet was commonly accessible and software was still shared or sold on disk or tape. Even in the Internet era, KDE could take their GitHub down or, something, and so it's best to host your own copy.

While this is true, KDE also needs to meet its GPL requirements, so they're unlikely to take it down. (Just as github is unlikely to take their servers down.) In the worst case, you take your copy of the source and publish it somewhere then update the notice next to the object code download place per 6(d) in GPL3. 3(c) in GPL2 is even easier if you didn't modify the source.

(IANAL, but have had precisely this discussion with multiple lawyers and never had a different answer.)

ExcessBLarg!
Sep 1, 2001

Subjunctive posted:

While this is true, KDE also needs to meet its GPL requirements, so they're unlikely to take it down.
GPLv2 3c was intended for the case of casually making a copy of a disk of GPL binaries for someone without having to personally be on the hook for the "written offer" (3b) part. It also shouldn't apply in the case of "hosting precompiled binaries I generated" since the program was conveyed to you in source, not object form.

That Turkey Story
Mar 30, 2003

Plorkyeran posted:

TTS's proposal this time around is pretty amazing. It never would have occurred to me that passing a field of a tuple as an argument to an overloaded function based on a runtime-provided index was even possible, and it appears to fix all sorts of gross code that I've had to write.

Thanks! I have a draft of a revision I'm working on that updates the return type deduction mechanism and makes it even easier to create argument providers (you never have to manually forward along the template-template parameter aside from your initial std::call invocation-- it's managed automatically in the function that's given to the provider). It also makes the return type deduction mechanism more capable such that you can have a return type deducer that returns a variant of all of the return types.

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

ExcessBLarg! posted:

GPLv2 3c was intended for the case of casually making a copy of a disk of GPL binaries for someone without having to personally be on the hook for the "written offer" (3b) part. It also shouldn't apply in the case of "hosting precompiled binaries I generated" since the program was conveyed to you in source, not object form.

Ignoring the fact that it doesn't really matter what the FSF's intent was, the GPL is explicitly about distribution, and doesn't care who compiled anything.

GPLv2 section 0 posted:

Activities other than copying, distribution and modification are not covered by this License; they are outside its scope.

If you don't get object files when you get the source, then you need to give downstream a written offer to give them a URL with the source. Providing that URL has been widely held to be "a medium customarily used for software interchange" as required by 3b. GPL3's 6d is clearer on this topic, thankfully.

(You're not going to get busted for not following GPL2 2a, either.)

raminasi
Jan 25, 2005

a last drink with no ice
I've been away from C++ development for three years and I'm going to be interviewing for a C++ job soon. What's the best way to learn about all the new language poo poo I've missed in the interim? (I'll also be going from MSVC++ to clang, so the effective time away is even more than three years.)

fritz
Jul 26, 2003

raminasi posted:

I've been away from C++ development for three years and I'm going to be interviewing for a C++ job soon. What's the best way to learn about all the new language poo poo I've missed in the interim? (I'll also be going from MSVC++ to clang, so the effective time away is even more than three years.)

Scott Myers' "Effective Modern C++" is pretty good.

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today

ExcessBLarg! posted:

The reality is that participating in open source is something that one has to value doing, not be compelled to do. For example, Apple and Google do a lot of participation in open source projects, often where licenses (Apache, BSD, MIT, etc.) do not obligate them to, and their participation is much better than riff-raff hardware vendors that post a might-be-the-correct-version of a Linux kernel tarball on their website somewhere. For that reason I think the GPL is outdated in many ways, and personally prefer simpler licenses. I don't have an issue releasing things under the (L)GPL if obligated to, but I generally prefer to stick an MIT license header on any actual source files I write.

I have the same licensing habits as you, but it's worth recognizing that the GPL isn't (just?) about compelling people to "participate." It's about ensuring that a motivated third party can come along and fix bugs in, add features to, or more broadly re-purpose a product. Consider all the abandoned games with die-hard fan communities that would love to be able to take over development, but can't because the code died with the original developers. Consider all the off-the-shelf routers out there running some variant of OpenWRT thanks to a Linux kernel tarball on a website somewhere. Consider all the TiVos and TiVoized hardware that isn't, and the introduction of the GPL3 (and, more broadly, the AGPL) to address that. For all that they're convenient and apolitical, BSD-style licenses do sacrifice some potential good.

raminasi
Jan 25, 2005

a last drink with no ice

fritz posted:

Scott Myers' "Effective Modern C++" is pretty good.

This looks perfect, thanks!

fritz
Jul 26, 2003

Is there a good way to get a partial specification of this:
code:
    template<typename T,
            template<typename, typename = std::allocator<T>> class Container>
            std::pair<T, T> f(const Container<T>& data) {
     // stuff
    };
In particular, I want to do something special when T is a certain class, something like:

code:
   class C {};
    // V1
    template<C,
            template<C, typename = std::allocator<C>> class Container>
    std::pair<C, C> meanAndVariance(const Container<C> &data) {
    // special stuff
    }
    // V2
    template<class Container>
            std::pair<C, C> f(const Container<C>& data) {
     // special stuff
    };
V1 doesn't build, and V2 doesn't get called.

It looks like I need a "template template parameter"?

VikingofRock
Aug 24, 2008




Ralith posted:

I have the same licensing habits as you, but it's worth recognizing that the GPL isn't (just?) about compelling people to "participate." It's about ensuring that a motivated third party can come along and fix bugs in, add features to, or more broadly re-purpose a product. Consider all the abandoned games with die-hard fan communities that would love to be able to take over development, but can't because the code died with the original developers. Consider all the off-the-shelf routers out there running some variant of OpenWRT thanks to a Linux kernel tarball on a website somewhere. Consider all the TiVos and TiVoized hardware that isn't, and the introduction of the GPL3 (and, more broadly, the AGPL) to address that. For all that they're convenient and apolitical, BSD-style licenses do sacrifice some potential good.

As someone who knows very little about licenses, what is the difference in the licenses that causes this?

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed

fritz posted:

Is there a good way to get a partial specification of this:
code:
    template<typename T,
            template<typename, typename = std::allocator<T>> class Container>
            std::pair<T, T> f(const Container<T>& data) {
     // stuff
    };
In particular, I want to do something special when T is a certain class, something like:

code:
   class C {};
    // V1
    template<C,
            template<C, typename = std::allocator<C>> class Container>
    std::pair<C, C> meanAndVariance(const Container<C> &data) {
    // special stuff
    }
    // V2
    template<class Container>
            std::pair<C, C> f(const Container<C>& data) {
     // special stuff
    };
V1 doesn't build, and V2 doesn't get called.

It looks like I need a "template template parameter"?

You can only partially specialize types and not functions, so to partially-specialize a function you have to make it a non-templated static member of a templated struct. You also have the syntax for partial specialization wrong; it's template<typename T> struct Bar<T, Foo> { ... }; to partially-specialize template<typename T, typename U> struct Bar;.

feedmegin
Jul 30, 2008

VikingofRock posted:

As someone who knows very little about licenses, what is the difference in the licenses that causes this?

BSD licences allow you to take the source to <x>, do what you like with it, incorporate it in your own product, and not release any of the changes you have made. At most they compel you to say that you used product <x> in your stuff.

The GPL does not allow you to do this thing, it's the explicit reason it came into being.

ExcessBLarg!
Sep 1, 2001

Ralith posted:

It's about ensuring that a motivated third party can come along and fix bugs in, add features to, or more broadly re-purpose a product.
The GPL, as it applies to, say, the Linux kernel fails to ensure that because enforcement is so weak. The BusyBox guys have made some decent efforts there, and the GPL-as-applied-to-Linux did spur consumer grade router development with the original Linksys WRT, sure. But there's hundreds of Linux devices pumped out of China that don't distribute source at all with no repercussion. You might argue that this isn't a failing of the license itself as enforcement is the responsibility of the copyright holders, which is fair. But Linux is also by far the largest and most-successful GPL project, so it's hard to evaluate the actual benefits of the license today when it's biggest example no longer represents the ideal.

Even when companies try to comply with the GPL, often source tarballs are missing files or don't correspond to the exact source revision shipping on a device, making it difficult or impossible to patch or update. The best participants are those who do development out in the open (public repos) and/or make efforts to commit code to upstream. Perhaps they're willing to do those things because the GPL affords them some protection that BSD/MIT-style licenses don't, but the GPL certainly doesn't obligate them to do those things. Personally I got tired of having to reverse engineer changes made to incomplete and otherwise unmaintainable source distributions, and so I don't expect to be able to hack on products unless I know they're coming from a community player.

fritz
Jul 26, 2003

Plorkyeran posted:

You can only partially specialize types and not functions, so to partially-specialize a function you have to make it a non-templated static member of a templated struct. You also have the syntax for partial specialization wrong; it's template<typename T> struct Bar<T, Foo> { ... }; to partially-specialize template<typename T, typename U> struct Bar;.

Well, phooey. Thanks!

22 Eargesplitten
Oct 10, 2010



I've found something in an enum declaration that is really confusing to me.

code:
    enum ERP_Result
    {
        rpNone = 0,
        rpOriginInside = 1,
        rpOriginOutside = 2,
        fcv_forcedword = u32(-1)
    };
I get the first three, but what's the last one? An unsigned integer can't be -1, because the range is 0-whatever. What's it doing? I presume it's some sort of "This is hosed up" thing, but I'm not sure how it even works to assign an unsigned integer to be negative, wouldn't it look at that and give up?

Joda
Apr 24, 2010

When I'm off, I just like to really let go and have fun, y'know?

Fun Shoe

22 Eargesplitten posted:

I've found something in an enum declaration that is really confusing to me.

code:
    enum ERP_Result
    {
        rpNone = 0,
        rpOriginInside = 1,
        rpOriginOutside = 2,
        fcv_forcedword = u32(-1)
    };
I get the first three, but what's the last one? An unsigned integer can't be -1, because the range is 0-whatever. What's it doing? I presume it's some sort of "This is hosed up" thing, but I'm not sure how it even works to assign an unsigned integer to be negative, wouldn't it look at that and give up?

You will probably get a compiler warning about casting a signed integer to an unsigned integer, but it won't stop it from compiling. What it means is that you get the highest possible value (32 true/1/high values in memory, since that is how -1 is represented in binary with 2's complement.)

E: The highest possible value for uints and -1 for signed ints are typically used for default cases/error codes.

Joda fucked around with this message at 22:05 on Jun 11, 2016

Klades
Sep 8, 2011

22 Eargesplitten posted:

I've found something in an enum declaration that is really confusing to me.

code:
    enum ERP_Result
    {
        rpNone = 0,
        rpOriginInside = 1,
        rpOriginOutside = 2,
        fcv_forcedword = u32(-1)
    };
I get the first three, but what's the last one? An unsigned integer can't be -1, because the range is 0-whatever. What's it doing? I presume it's some sort of "This is hosed up" thing, but I'm not sure how it even works to assign an unsigned integer to be negative, wouldn't it look at that and give up?

In general, the only difference between a signed and unsigned number is how it's interpreted. An unsigned 32-bit int of value 4294967295 and a signed 32-bit int of value -1 are both 11111111111111111111111111111111.
Sometimes you can gleefully interchange the two, but often you get compiler warnings about it now, and some other languages won't let you do it unless you jump through a hoop or two.

22 Eargesplitten
Oct 10, 2010



Ah, okay. It's probably some weird error / warning generating thing they put in there without explaining it. This is a terrible, terrible engine I'm working with. I'm trying not to be too harsh on it because it's almost old enough to drive, but they just never comment anything. Thanks.

Qwertycoatl
Dec 31, 2008

22 Eargesplitten posted:

I've found something in an enum declaration that is really confusing to me.

code:
    enum ERP_Result
    {
        rpNone = 0,
        rpOriginInside = 1,
        rpOriginOutside = 2,
        fcv_forcedword = u32(-1)
    };
I get the first three, but what's the last one? An unsigned integer can't be -1, because the range is 0-whatever. What's it doing? I presume it's some sort of "This is hosed up" thing, but I'm not sure how it even works to assign an unsigned integer to be negative, wouldn't it look at that and give up?

The name "fcv_forcedword" makes me think it's there to force the enum's underlying type to be 32 bits wide, for some reason.

hackbunny
Jul 22, 2007

I haven't been on SA for years but the person who gave me my previous av as a joke felt guilty for doing so and decided to get me a non-shitty av

Qwertycoatl posted:

The name "fcv_forcedword" makes me think it's there to force the enum's underlying type to be 32 bits wide, for some reason.

enums can be of different sizes on different compilers, Borland C++ for example used the smallest type that could represent all values (ERP_Result would have been the size of a char, for example). It's very common to put a semantically meaningless value in an enum that only serves to force a certain size, so that the enum can be safely used as a struct member or function argument, even if library and application are compiled with different compilers. Modern C++ lets you specify the underlying type of an enum explicitly, but lots of code will use the old way for a long time

Xerophyte
Mar 17, 2008

This space intentionally left blank
uint32_t(-1) is a relatively common way of getting the largest 32bit number. The standard guarantees that, when casting signed to unsigned integral types: "If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2^n where n is the number of bits used to represent the unsigned type)." You could use std::numeric_limits or something in modern C++ (or just UINT_MAX), but casting -1 to an unsigned type is extremely common so get used to seeing it.

Here that's used to force the enum to have an underlying type other than int, in this case unsigned int on most systems. Since C++11 you can explicitly specify the underlying type of an enum, but adding an enumerator for the top end of the range isn't uncommon in older code if you want to force the underyling enum type (for ABI stability or whatever).


E: Hrm, reading more closely there aren't actually any rules for the underlying type of an unscoped enum of non-fixed type (scoped enums default to int). It guarantees that the type be convertable to, quoting cppreference, "the first type from the following list able to hold their entire value range: int, unsigned int, long, unsigned long, long long, or unsigned long long." However, the valid range for assigning to the enum type would only be that of the smallest bitfield able to hold its values, so [0..3] without the forcer in this case. Assigning values outside of that range is undefined behavior. I imagine that the vast majority of implementations will use an underlying type of int and do the obvious, but they'd be free not to.

Xerophyte fucked around with this message at 00:31 on Jun 12, 2016

feedmegin
Jul 30, 2008

Of course that enum could go pear shaped on a 64 bit platform where an enum could be 64 bits...

Bonfire Lit
Jul 9, 2008

If you're one of the sinners who caused this please unfriend me now.

feedmegin posted:

Of course that enum could go pear shaped on a 64 bit platform where an enum could be 64 bits...
In C, but not in C++; C++ provides that "the underlying type shall not be larger than int unless the value of an enumerator cannot fit in an int or unsigned int" (other than that, which exact type is chosen is implementation-defined). Of course this assumes that you're not on an ILP64 platform.

Bonfire Lit fucked around with this message at 23:27 on Jun 13, 2016

Captain Cappy
Aug 7, 2008

So I have to design an API (it isn't going to be used don't worry) and I was wondering about the fastest way to write a setter for something that has a move constructor available. Is this template pretty much guaranteed to be the fastest it can be? There's obviously some downsides to templates (compile time, exposed code to class user, compiler errors), but I have a fever, and the only prescription is fast code. Note: I didn't compile this but its what I remember perfect-forwarding looking like.

code:
template <typename Class>
void
SetThing(Class &&aObject)
{
  thing = std::forward(aObject);
}

Captain Cappy fucked around with this message at 22:43 on Jun 15, 2016

eth0.n
Jun 1, 2012

Captain Cappy posted:

So I have to design an API (it isn't going to be used don't worry) and I was wondering about the fastest way to write a setter for something that has a move constructor available. Is this template pretty much guaranteed to be the fastest it can be? There's obviously some downsides to templates (compile time, exposed code to class user, compiler errors), but I have a fever, and the only prescription is fast code. Note: I didn't compile this but its what I remember perfect-forwarding looking like.

This requires a move assignment operator, but most things with one should have the other anyway. Otherwise, looks good, except you need template parameter <Class> added to forward.

Adbot
ADBOT LOVES YOU

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today

Captain Cappy posted:

So I have to design an API (it isn't going to be used don't worry) and I was wondering about the fastest way to write a setter for something that has a move constructor available. Is this template pretty much guaranteed to be the fastest it can be? There's obviously some downsides to templates (compile time, exposed code to class user, compiler errors), but I have a fever, and the only prescription is fast code. Note: I didn't compile this but its what I remember perfect-forwarding looking like.

code:
template <typename Class>
void
SetThing(Class &&aObject)
{
  thing = std::forward(aObject);
}

This isn't great, because you've now got a function template that will accept arguments of any type whatsoever, and then spit out a verbose template error. Instead, you can just define two non-template functions, one taking a const reference and the other taking an rvalue reference. Overload resolution will select the correct one and you can keep the implementations elsewhere if you want.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply