GCC 7 C++ 17 support for folding expressions - c++

The following snippet will compile in GCC 8+, but fails to compile in GCC 7.
template <typename... THINGS>
struct A
{
explicit A(THINGS *... things)
{
(..., [thing = things](){}());
}
};
int main()
{
int thing;
const auto thingy = A{&thing};
}
godbolt
The stated failure is that the parameter pack isn't being expanded: parameter packs not expanded with '...'.
Checking the GCC standards compliance page, fold expressions should be supported in GCC 7.
Is there another flag i need besides std=c++17? (i didn't see one)
Is the standard not yet completely implemented? (i didn't see anything indicating that)
Can i make this work, or is this just a GCC 7 bug i'm going to have to work around?

This is a GCC bug, originally reported in version 8.01, fixed in version 8.2. It seems that the bug also occurs when fold-expressions are not used (the C++11-era "expander trick" mentioned by NathanOliver doesn't work either), so you'll have to use a longer workaround that doesn't require expanding a template parameter pack that is inside a lambda capture. For example:
template <typename THING>
void do_it(THING* thing) {
[thing]{}();
}
explicit A(THINGS *... things)
{
(..., do_it(things));
}

This is a GCC bug. Found the tracked issue, fixed in 8.2.

Related

Function with auto parameter compiles using GCC but does not compile using Visual C++

Please considere the following code-snippet:
#include <iostream>
void print(auto arg) {
std::cout << arg << std::endl;
}
int main() {
print("Hi");
return 0;
}
As you can see here (https://godbolt.org/z/2GSrXs) using GCC the code compiles and runs fine.
As you can see here (https://godbolt.org/z/rtR6w9) using Visual C++ the code does not compile and results in the error message:
<source>(3): error C3533: a parameter cannot have a type that contains 'auto'.
It seems to me that this feature has not jet been implementet in Visual C++?
Additionally I was not able to find the compiler feature in the following list:
https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance?view=vs-2019. So I am not sure if the Microsoft developer have the feature on their ToDo List?
Functions receiving auto is a C++20 feature. It must be enabled with /std:latest. However, MSVC only has partial support for this syntax at this time, so not all declaration using this feature will work.
GCC has supported auto in function parameters since early C++14 days as an extension.
You can read more about this C++20 feature reading P1141R2: Yet another approach for constrained declarations
Remaining in C++14 standard, you can use the following lambda instead of your function:
auto print = [](auto arg) {
std::cout << arg << std::endl;
};

MSVC's (seem not perfect) support for constexpr

I am making the naive wheel of type traits's is_base_of. And Here's a minimal demo about my implementation(didn't consider robustness, is_class...).
#include <type_traits>
#include <cstdint>
struct A
{
};
struct B : A
{
};
template
<typename T, typename U>
struct IsBaseOf {
constexpr static bool Test(T* t)
{
return true;
}
constexpr static bool Test(...)
{
return false;
}
constexpr static bool value = IsBaseOf<T,U>::Test(static_cast<U*>(nullptr));
};
int main()
{
static_assert(IsBaseOf<A, B>::value, "Pass");
}
This demo can be compiled by gcc/clang but cannot be compiled by MSVC.
http://rextester.com/ATOC6638
http://rextester.com/IWU81465
When i type it on my laptop's Visual Studio 2015(with update patch 3). It cannot be compiled either, the IDE reminds me that "expression must have constant value" before compiling.
So I wonder how's MSVC support for constexpr, or is my code wrong?
This is almost certainly a bug in MSVC. Especially previous versions had numerous issues with constexpr. Here's just a bunch of them for example. Support for many new features is not all that great yet in MSVC. But it's getting better by the minute. You'll want to always use the latest version to try out this sort of stuff. VisualStudio 2017 compiles this code just fineā€¦
Your code compiles with Visual Studio 2017 (cl version 19.15.26726).
You could try adding /std:c++14 or /std:c++latest compiler switch.

Lambdas in variadic templates

Using Microsoft Visual C++ 2013 (12.0), I am encountering compile-time errors when using a lambda in a constructor in a variadic template. I have managed to boil it down as shown below (see the lines with the error comments). It appears to be a bug in 12.0 that is not present in 14.0. I haven't tried other versions. Is there any documentation on this bug, perhaps in the form of a release note that clarifies the conditions under which this bug occurs and which states that it has been explicitly fixed?
#include <functional>
// a simple method that can take a lambda
void MyFunction(const std::function<void()>& f) {}
// a simple class that can take a lambda
class MyClass
{
public:
MyClass(const std::function<void()>& f) {}
};
// non-templated test
void test1()
{
MyFunction([] {}); // OK
MyClass([] {}); // OK
MyClass o([] {}); // OK
}
// non-variadic template test
template<typename T>
void test2()
{
MyFunction([] {}); // OK
MyClass([] {}); // OK
MyClass o([] {}); // OK
}
// variadic template test
template<typename... T>
void test3()
{
MyFunction([] {}); // OK
MyClass([] {}); // OK
MyClass a([] {}); // error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
// error C2440: 'initializing' : cannot convert from 'test3::<lambda_12595f14a5437138aca1906ad0f32cb0>' to 'int'
MyClass b(([] {})); // putting the lambda in an extra () seems to fix the problem
}
// a function using the templates above must be present
int main()
{
test1();
test2<int>();
test3<int, int, int>();
return 1;
}
Edit/Update: MSVC 2013 compiler seem to have this bug, latest versions fixed that. GCC and clang compilers don't show any error.
I can't say is that bug or not, back days Microsoft was not so eager to latest C++ standards, it was two steps behind GCC and CLang, and it's not a surprise to know that no-one implement a whole standard in one compiler update. Some stuff from std library may be partially implemented, for example Visual Studio usually implements new features under std::experimental namespace (filesystem for VS2013), but something like compiler lexemes can't be added that way.
For common information about standard compatibility I suggest to use compiler support article https://en.cppreference.com/w/cpp/compiler_support/11 (MSVC means _MSC_VER definition) and
https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance more for detailed information about Visual Studio. Here https://en.wikipedia.org/wiki/Microsoft_Visual_C++#Internal_version_numbering you can find _MSC_VER version along with related Visual Studio version, source is https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros.
Based on those articles I believe that your problem lays in between "Variadic templates" and "Lambda expression" both are fully supported from Visual Studio 19.0, searching _MSC_VER 1900 in wiki that means Visual Studio 2015 (Update 2, if to be precise according to Microsoft article).
vs2015 can be compiled normally, because vs2015 can fully support the c++11 standard, you can consider upgrading your vs

Curiously Recursive Template Pattern in GCC 3.4 (MoSync to be exact)

I'm currently trying to write an Artemis like game component/entity system in C++. I was planning on getting this system to work with a cross platform tool for writing applications on Android and iOS called MoSync.
Unfortunately MoSync currently uses an old version of GCC and when porting the library that I had been testing in Visual Studio, I got a whole bunch of errors. Most of these I could solve, but there is one bug with templates that I can't get my head around.
I wrote a small example
template <typename T>
struct Base
{
static int type;
};
struct Derived : public Base<Derived>
{
};
template <typename T>
int Base<T>::type(-1);
extern "C" int MAMain()
{
Derived d;
d.type = 0;
}
My library uses the Curiously Recursive Template Pattern for defining Components. This example compiles fine in GCC 4.4 and Visual Studio 2010. However when I try to compile this in MoSync (which uses GCC 3.4.6) I get this linker error
C:\MoSync\workspace\pede\main.cpp: Error: Unresolved symbol '__ZN4BaseI7DerivedE4typeE',
Is there a workaround to get this to work in this compiler, or will I have to find another way to define my Components?
Edit*
In fact I can make this error occur with an even simpler example:
template <typename T>
struct Component {
static int t;
};
template <typename T>
int Component<T>::t(-1);
extern "C" int MAMain()
{
Component<int>::t = 0;
}
Gives this error
C:\MoSync\workspace\Components\main.cpp:9: Error: Unresolved symbol '__ZN9ComponentIiE1tE',
I guess this might not have anything to do with the Curiously Recursive Template Pattern at all. What can I do to get this to compile under GCC 3.4.6?
According to this bug report on the gcc bugtracker, the problem is caused by specifying a default value in the static variable definition. The code should link if you remove the initialisation as so:
int Base<T>::type;
The bug report seems to have been resolved as not a bug. Despite this, your samples compile fine in GCC 4.4.
To work around this, you can use a class type with a constructor that will automatically initialise itself.
Does adding
int Base<Derived>::type(-1);
helps ?
gcc 3.4 is really starting to be old and don't coep well with template sorcery.

Do Ideone and Codepad really not support C++03?

My question is related to Prasoon's question about non POD types and value initialization.
I tried the following code on online compilers like Ideone and Codepad but the executables gave runtime error on both the sites.
#include <iostream>
#include <cassert>
struct Struct {
std::string String;
int Int;
bool k;
};
struct InStruct:Struct
{
InStruct():Struct(){}
};
int main()
{
InStruct i;
assert ( i.Int == 0);
std::cout << "Hello";
}
Ideone Output here
Codepad Output here
Does that mean neither of them support C++03 value initialization feature?
Does that mean neither of them support C++03 value initialization feature?
Yes.
Prior to version 4.4, GCC did not completely support value initialization (the Boost GCC compatibility header explains this and has links to the relevant GCC defect reports; see line 77).
If your code needs to be portable, you should be very careful relying on value initialization; GCC did not support it fully until recently and Visual C++ does not fully support it even in its latest version, Visual C++ 2010.
The declaration
InStruct i;
does not invoke value initialization
$8.5.3/10 - "An object whose
initializer is an empty set of
parentheses, i.e., (), shall be
value-initialized."
If you want to value-initialize, you would require an expression something like
assert(InStruct().Int == 0);
Try it now! - Ideone supports GCC-4.5.1