Final features of C++17
meetingcpp.com
meetingcpp.com
Trigraphs [1] are gone. Good riddance, they're just used for pointless pranks anyways. Otherwise they just seem to cause issues, there's always someone who didn't know about them at all.
Also "unexpected_ownership_move" err... "auto_ptr" is gone [2]. Yeah, I know, there's nothing inherently wrong with it and you knew how to use it correctly...
[1]: http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2014/n398...
[2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n419...
This also makes the standard smaller.
Man... Who do you work for? If I used that as a reason for a refactoring my boss would laugh at me (and he's technical) . I imagine his boss would glaze over for a bit and then ask him to leave his office.
Speaking as an engineer, some of us have a tendency to want to refactor and polish code past the point where we should ship it and move on to something else. Management also has a tendency to view refactoring as unproductive and hurtful to the company's bottom line. Both are very reasonable positions. In most cases, the best strategy tends to be in the middle somewhere.
The auto_ptr class is gone from C++17 because it is error-prone to use it and there are better alternatives. However, I don't need to explain the intricacies of auto_ptr to my boss. I can just say something like, "We want to keep up with the latest industry best practices and standards. Some simple changes to our code base will reduce the chance for bugs and reduce support costs, and make it easier to develop new features."
The fact that auto_ptr has been removed from the standard entirely sends a stronger signal that you really should stop using it. Which is a good signal to send.
It's why most C++ compilers these days don't even enable them by default. Kicking them out of the Standard is merely the recognition of that practice.
[0] https://en.wikipedia.org/wiki/Digraphs_and_trigraphs#Removal...
See also: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n291...
It's remarkable that such systems still exist (and are apparently being updated, without their foundational cracks fixed) still today!
FFS, if you somehow find both of these to be true, preprocess your source to convert trigraphs to the corresponding glyphs, and to a character encoding that supports them. I can't possibly believe that they're running a C++17 compiler on a system that has no support for such a character set.
At least it still exists much like some of the other ones like the filesystem ts. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n458...
I'd rather the committee focus on longstanding language core issues than add everyone's favorite library.
Libraries are fine, but the problem here might be about OS or platform.
If I have a reason to use the language I can learn the build tooling (which last time I used C++ they were very, very old and overly complex IMO; nothing easy like rust's).
If you want to drive adoption of C++ you need to lower friction to using it. This works in every single thing ever created. If you can get more features into the STL that the vast, vast majority of languages have built in and get good tooling you'll have a very easy way for someone to jump into the language.
Alternatively you can continue to keep the friction high and address "language core issues" instead of making the STL have parity with all other popular languages. I think that approach is terrible but only if your goal is to grow the community of developers. But that's just my opinion of someone who loved C++ 10 years ago but had to move to higher level languages just to get stuff done, quickly and efficiently.
[1] Those are ioctlsocket vs ioctl, and closesocket vs close. A basic TCP implementation can be cross platform with as little as 2 #ifdef/#endif blocks.
Structured bindings seem like one of those things that was just forgotten in previous standards, I'm glad it's here now. The syntax is a matter of taste, I guess.
I'm also quite excited about variants, they probably won't be used much but sometimes they're just what one needs. Having them without requiring boost is nice.
if constexpr (false) { static_assert(false); }
Will fail to compile because the static_assert will trigger. This seems strange to me, anybody have an idea what the reasoning here is? if constexpr (foo) {
static_assert(!foo || /* assertion */);
} else {
static_assert(foo || /* assertion */);
}
(this gets ugly fast with lots of else-ifs, but it's a workaround - I don't know why you'd ever need it, though) template<typename T>
void func(T x) {
if constexpr ( std::is_same< T, ClassWithMemberF>::value ) {
x.f();
}
}
will not work if you pass in a type for x that does not have a member function f. Is my understanding right? If so, constexpr if is not nearly as nice as I thought... if (false constexpr) { random gibberish }
will not compile, and that's a good thing. I think it would be odd to "hack" static_assert for this special case. if constexpr ( COND) { CODE };
would compile even if CODE only compiles when COND is true. There a lot of nice use cases for that, and that's how the static_if in D works.You can still do this sort of stuff with template overloads, but it's much more cumbersome.
if constexpr (condition) {
print("yes");
}
While this wouldn't: if constexpr (condition) {
print({
}
At least that's my understanding.[1] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p029...
template<class T>
class foo;
template<>
class foo<int> {
static_assert(false, "bad");
};
template<>
class foo<float> {};
template<class T>
foo<T> foo_fn(T v) {
if constexpr (std::is_same<T, int>::value) {
return foo<int>{};
}
else if constexpr (std::is_same<T, float>::value) {
return foo<float>{};
}
else {
return foo<T>{};
}
}
foo_fn(1.0); // <-- does not trigger static assert
foo_fn(1); // <-- triggers static assert
This is consistent with the wording of the proposal. template<>
class foo<int> {
static_assert(false, "bad");
};
Reason: "false" is not a dependent name, so the compiler is allowed to check the static_assert when the template is being declared.(Of course since this is a full specialization, there are no dependent names.)
See C++14 Standard §14.6.2 (Dependent Names) or http://en.cppreference.com/w/cpp/language/dependent_name (not sure how accurate that page is, though).
P.S: It might compile with Microsoft's Visual Studio, but only because that compiler doesn't implement two-phase name lookup, effectively turning every name into a dependent name.
Also this dependent name behavior of static_assert seems to be a precedent for always checking static_assert in constexpr if.
This implementation did not fly for C++'s goal of being high performance, and thus the new standardized variant is done quite differently.
The interface is very similar, but the implementation is ofc using C++17 and not C++03.
Are there any C++14 variant implementations compatible with boost::variant and std::variant which are based on variadic templates? I'd love to move to a more modern implementation if possible.
Taking very normal so-what code and moving it into the standard is pretty much the point. Having variant in std:: lets new code use variants without adding a boost dependency. I say that without knocking on boost. Fewer dependencies are always better.
As an example, I've been exploring Sean Parent's idea of concept-based polymorphism that allows you to implement "virtual functions" that get bound at compile time. To make this scheme explicit, I need to assert in the base class that all my "derived" classes implement a method with a certain signature. Does C++ allow me to do this?
The C++ template system is already a Turing-complete functional programming language and has been since C++'s inception. I see nothing wrong with making this language's syntax more convenient.
> half-baked and then abandoned like other C++ features (virtual inheritance for example)
Virtual inheritance has its place. It's part of the language and works fine. What would you change?
I've seen this argument pop out time and again as if it was a mantra of sorts, and more often than not it comes from someone with a background almost exclusively founded on Java.
Their line of reasoning essentially boils down to "Java doesn't support it, the people behind Java said something about it, therefore it's bad".
But C++ isn't Java, nor does Java dictate what is correct or what makes sense.
Particularly when the only assertion you could come up with to criticize multiple inheritance was a comment that had nothing to do with C++ or even OO programming, but only to do with your personal taste regarding your superficial impressions regarding software design.
Here's the issues I take with virtual inheritance:
1. It complicates the vtable and function/member calls leading to another level of indirection, so from a performance perspective it's a negative mark.
2. The more fundamental problem is that you've botched the hasA vs isA association. If you have two classes that share a base class then that base class should be refactored into a component that can then be used as a member without polluting the class hierarchy. This leads to better composability since you can now pass this object around without pulling a whole class hierarchy with it.
You're welcome to use virtual inheritance all you want in your projects but much like knowing what subset of C++ to use(and what not) you'll never see it in code I work on.
No you haven't.
In many senses, C++ inheritance is just shorthand for composition. That's why things like private inheritance are useful. Through this lens, virtual inheritance is automatic composition in which multiple composed objects each have a pointer to some shared object (the virtual base). It doesn't mess with hasA vs. isA at all.
> knowing what subset of C++ to use
This idea that a good coding standard necessarily bans parts of C++ has done massive damage to the C++ community. The correct subset of C++ to use is C++. Turning off parts of the language is just a cheap way to look sagacious while infantilizing developers. Every feature has its place.
There's a been a fair number of projects I've worked on where exceptions and RTTI introduced too much memory/perf overhead so we explicitly didn't use them. I don't feel like we were worse off for not having them.
C++-without-exceptions is a very different and much worse language.
Considering LLVM takes the same stance[1] and they're the ones implementing language features that's good enough for me.
[1] http://llvm.org/docs/CodingStandards.html#do-not-use-rtti-or...
Well, it's a preference, not a hard requirement. I'll hold my nose and work on such a codebase if there are other reasons, like the project itself being very interesting.
> Considering LLVM takes the same stance
IMHO, that's a mistake. But LLVM is an example of a project that's compelling enough to work on despite what I consider a set of poor language choices.
Of course (C++14, possibly C++11):
#include <type_traits>
template <typename T, typename... Params>
struct HasFoo {
// SFINAE will disable this function template if U has no method foo(float)
template <typename U>
static constexpr bool check(decltype(std::declval<U>().foo(std::declval<Params>()...))*)
{
// We don't check foo's return type here
return true;
}
// Fallback if above function template is disabled
template <typename U>
static constexpr bool check(...)
{
return false;
}
static constexpr bool value = check<T>(0);
};
template <typename D>
struct Base {
Base()
{
static_assert(HasFoo<D, float>::value, "D must implement 'foo(float)'");
}
};
struct Derived {
void foo(int)
{
}
};
Since this essentially simulates a method call, implicit conversions work, as does overloading "foo".As you have to implement "HasFoo" for every method you check, a macro will come in handy, say MAKE_METHOD_CHECK(Foo, bool, float)
I added some comments, feel free to ask if something is not clear :-)
If that's all you want just write:
void foo()
{
static_cast<Derived&>(*this).foo_impl();
}
When the derived class doesn't have any method "foo_impl" (or no "foo_impl" with a suitable signature), you will get a compile-time error.No need for the static_assert, that was just because KKKKkkkk1 asked whether checking for the existence of a method at compile-time was possible.
Compile-time polymorphism is essentially duck typing: If it quacks like a duck you can treat it as one. If it doesn't quack like a duck, but you still treat it as one you get a compiler error.
template <typename D>
class Base {
...
};
and then: class Derived: public Base<Derived> {
...
};
This is called the https://en.wikipedia.org/wiki/Curiously_recurring_template_p...As the call is resolved at compile time, simply calling the function will cause a compile error if the derived class doesn't implement it. The error message might not be the prettiest, but there are ways to improve that.
"auto [a , b , c] = getvalues();
"The braces are needed, getvalues returns a tuple. std::pair is not mentioned in the proposal, so its unclear if this works with pair, which is returned by the STL in some insert methods."
Destructured bindings will work with arrays; plain aggregate structs; and any class that offers a specialization of std::get<>(), so both std::tuple and std::pair are supported as a consequence. (C++11 added std::get<>() for std::pair).
Otherwise, if the expression std::tuple_size<E>::value is a well-formed integral constant expression, the number of elements in the identifier-list shall be equal to the value of that expression
(E is the return type of "getvalues" in squidbidness's example, the initializer-list is "a, b, c".)
I hope I will manage to try modules in MSVC before that time.
------ Old comment:
Makes sense it's undefined behavior, because address 0 is involved. Although I'd guess compiler implementations might just drop whole statement, because length is 0.
Zero length memory copy is a no-op.
Just like static zero iteration loop. They become zero instructions. (Except of course initialization that affects something outside loop scope.)
Edit:
Changed my mind after learning about the tricky UB pathway: If compiler can statically prove memcpy length argument to be zero, it can ALSO prove both argument pointers to be not NULL!
Ouch!
Why handle 0x0 differently?
Not as mechanism that can cause serious bugs, when the compiler can statically prove length argument to be 0 and you can have NULL arguments as input.
Calls to memcpy with zero length are definitely not uncommon. Macros are an obvious way, but it's worse. All you need is a data flow where compiler can statically prove that all paths lead to zero length argument.
I have to agree it's very scary that memcpy(NULL, NULL, 0) is undefined.
Sure about that?
It really should be a no-op. The C and C++ standards are seriously broken in this respect, and compiler authors take advantage of this brokenness to get away with miscompiling programs that, to anyone with common sense, are fine.
The C and C++ standards must be changed to explicitly state that memory operations on zero bytes do nothing regardless of whether the inputs are valid pointers.
It seems so obvious after reading that. Should always ask oneself "what can the compiler prove as a consequence of this undefined behavior?".
So, you're right, memcpy(NULL, NULL, 0) should be defined as a no-op.
Zero-length memcpy pathway to UB is not obvious, because whether the whole thing is UB depends on whether compiler can statically prove the length to be zero. Ugh.
It's also possible you're confusing undefined behavior with implementation defined behavior.
It's used everywhere in real life C++ code.
quotemstr got a very good point and I'm grateful for the heads up.
C++ is not 100% compatible with C.