Why constexpr implicit conversion doesn't always work? - c++

#include <iostream>
struct Index {
constexpr operator int() const { return 666; }
};
template <int i> void foo() {
std::cout << i << std::endl;
}
void wrapper(Index index) {
foo<index>();
}
int main() {
Index index;
// foo<index>(); // error: the value of ‘index’ is not usable in a constant expression
wrapper(index);
}
Hello, everyone.
I'm using a constexpr conversion of a variable "index" to an int value, which is substituted to a "foo" templated function.
If I directly call foo<index>() from "main", I get a compiler error.
If the same call is done from the "wrapper", then everything compiles and works fine.
What am I missing there?
Compile command: g++ -std=c++14 main.tex with g++ (GCC) 5.3.1 20160406 (Red Hat 5.3.1-6).

A very similar error was reported here. It was first reported with GCC 4.9.0
In the analysis provided:
This is a GCC bug. It appears to be some sort of confusion in the way GCC handles internal linkage non-type template parameters of pointer type.
It has since been resolved.

Related

thread_local template variable of struct inside anonymous namespace fails to link?

The following example program uses a thread local template variable, and instantiates it using a type inside an anonymous namespace. This produces a linker error in gcc. In clang it actually compiles but does not run correctly.
#include <stdio.h>
template<typename T>
struct container {
container() { printf("construct: %p\n", this); }
~container() { printf("destruct: %p\n", this); }
};
template<typename T>
thread_local container<T> storage;
namespace {
struct bar {};
}
int main() {
auto& ref1 = storage<bar>;
auto& ref2 = storage<bar>;
}
On gcc this fails with a link error:
a.cpp:6:2: warning: ‘container<T>::~container() noexcept [with T = {anonymous}::bar]’ used but never defined
~container() { printf("destruct: %p\n", this); }
^
/tmp/ccgh0P15.o: In function `__tls_init':
a.cpp:(.text+0xa9): undefined reference to `container<(anonymous namespace)::bar>::~container()'
With clang the program compiles but produces very troubling output:
construct: 0x7fb8d1c003d0
construct: 0x7fb8d1c003d0
destruct: 0x7fb8d1c003d0
destruct: 0x7fb8d1c003d0
Are there some rough edges surrounding thread_local/templated variables that I am running into here? I am unclear why this would ever produce a link error (the link error disappears if I remove thread_local). In the case of clang how could a double destroy of an object with static storage duration be anything but a compiler bug? In clang the issue disappears if I remove the anonymous namespace OR the thread_local specification, OR by removing one of the references in main().
Can anyone shed some light on this, I am mainly just curious if I am misunderstanding something. Thanks!
EDIT:
clang++ -v
Apple LLVM version 10.0.0 (clang-1000.11.45.5)
g++ -v
gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04)

Array bound set by a function of a generic

I want to set the array length to be the minimum of a constant and a generic like this:
template <int foo> struct Bar{
void my_func( int const (&my_array)[std::min(5, foo)] ) { /*...*/ }
};
This code compiles with clang++ but not g++ and I need my code to work with both. The error g++ gives is: error: array bound is not an integer constant before ']' token. How I can set the length of this array to be the minimum of foo and 5?
When I use clang++ I run into the problem that I can't get anything to bind to my_array. I want to run something like:
int main() {
static const int var[5] = {0,1,2,3,4};
Bar<5> bar;
bar.my_func(var);
}
But when I try to compile this code in clang++ I get: error: reference to type 'const int [*]' could not bind to an lvalue of type 'const int [5]'.
If I get rid of the std::min() stuff and replace it with foo the code compiles and runs fine.
Notes:
To get this code to compile you'll need to #include <algorithm> or similar to access std::min.
I don't think that this being part of a template should matter but when I try similar things with non-template function such as:
const int const_five = 5;
void new_func( int const (&my_array)[std::min(5,const_five)] ) { /*...*/ }
g++ says: error: variable or field 'new_func' declared void and clang++ says candidate function not viable: no known conversion from 'const int [5]' to 'const int [std::min(5, const_five)]' for 1st argument which both look like similar problems.
For int const (&my_array)[std::min(5, foo)] to compile, you need a version of std::min which is constexpr. It is since C++14.
Check the default value for -std of gcc and clang you use (its version-dependant). Ultimately, compile with -std=c++14.
Provided by StoryTeller, a nice working MCVE.
Keep it simple:
[foo < 5 ? foo : 5]

is decltype required in trailing return using value of argument type

In trying to understand c++17 compliant code, i am confused by the following code in
which the function uses the value from integral_constant type argument in the
trailing return type. (please feel free to correct my terminolgy etc, trying to learn)
Two simple versions are illustrated below , with and without a decltype on the
argument in the trailing return.
Using Compiler Explorer https://godbolt.org/z/vqmzhu
The first (bool_from1) compiles ok on
MSVC 15.8; /std:c++17, /O2, /permissive-
and clang 8.7.0.0 and gcc 8.2; -std=c++17, -O2, -pedantic
with correct assembler output
The second (bool_from2) errors out on gcc,
It also shows Intellisense errors in VS but compiles without error.
I could not find anything in cppreference or standard draft, etc that would indicate to me that the decltype(atype) would be required for conforming code, however...???
My question would be is the decltype required.
Are my compiler flags correct for c++17 conformance checking.
CODE:
#include <utility>
namespace ns {
volatile bool vb;
template<bool B> struct bool_ : std::bool_constant<B> {};
// using decltype(btype) in trailing return compiles in all 3
template<typename Bool> constexpr auto bool_from1(Bool btype)
-> bool_<decltype(btype)::value> {
return bool_<btype.value>{};
}
void test1() {
static_assert( // simple test
bool_from1(std::true_type{}).value
);
vb = bool_from1(std::true_type{}).value; // check output
}
// without decltype in trailing return compile in VS and clang
// but errors out in gcc; and VS shows Intelisense errors but compiles
template<typename Bool>
constexpr auto bool_from2(Bool btype)
// ^ gcc 8.2 error: deduced class type 'bool_' in function return type
-> bool_<btype.value> {
// ^ gcc: invalid template-id; use of paramter outside function body before '.'
//^ VS Intellisense on btype: <error-constant>; a paramter is not allowed
return bool_<btype.value>{};
}
void test2() {
static_assert(
bool_from2(std::true_type{}).value
//^ gcc: bool_from1 was not declared in this scope
);
vb = bool_from2(std::true_type{}).value; // check output
}
}
This looks like a gcc bug and bug report: "Trailing return types" with "non-type template arguments" which could be "constant expressions" produce a parsing error seems to fit this case:
Consider the following snippet:
template <int>
struct bar {};
template <class I>
auto foo(I i) -> bar<i()> { return {}; }
int main()
{
foo([]{ return 1; }); // (0)
}
This compiles and works as intended on clang++5, but produces a
compile-time error on g++7:
prog.cc:5:25: error: template argument 1 is invalid
auto foo(I i) -> bar<i()> { return {}; }

Mystifying UB/segfault only on gcc - is the code ill-formed? [duplicate]

I have the following SSCCE:
#include <iostream>
#include <string>
void foo(const std::string &a) {
std::cout << a << std::endl;
}
template <typename... Args>
void bar(Args &&... args) {
[&]() {
[&]() {
foo(args...);
}();
}();
}
int main() {
const std::string x("Hello World!");
bar(x);
}
Under clang++ (3.9.1) this compiles and emits "Hello World". Gcc 6.3 fails with a segmentation fault under -O3.
I can fix the problem by explicitly passing the pointer and the pack by reference, replacing [&]() with [&args...](). However, up to now, I thought that [&] would do the same as listing all arguments one by one.
So what is going wrong here?
P.S:
This is not limited to -O3. -O0 does not segfault but does not return the expected result ("Hello World!"):
[:~/tmp] $ g++-6 -std=c++1z param.cpp && ./a.out
[:~/tmp] $
P.P.S: Further reduced SSCCE. Now I don't even get a diagnostic with -Wall -Wextra anymore.
I strongly suspect a g++ bug.
Here are some notes:
replacing std::string with any elementary type, e.g., int still does not work
clang and VC++ will work just as intended
not passing parameter pack by reference causes an internal compiler error with g++ 7.0.1 with the following output:
internal compiler error: in make_decl_rtl, at varasm.c:1304
...
Please
submit a full bug report, with preprocessed source if appropriate.
Please include the complete backtrace with any bug report. See
http://gcc.gnu.org/bugs.html for instructions.

GCC causes segfault for lambda-captured parameter pack

I have the following SSCCE:
#include <iostream>
#include <string>
void foo(const std::string &a) {
std::cout << a << std::endl;
}
template <typename... Args>
void bar(Args &&... args) {
[&]() {
[&]() {
foo(args...);
}();
}();
}
int main() {
const std::string x("Hello World!");
bar(x);
}
Under clang++ (3.9.1) this compiles and emits "Hello World". Gcc 6.3 fails with a segmentation fault under -O3.
I can fix the problem by explicitly passing the pointer and the pack by reference, replacing [&]() with [&args...](). However, up to now, I thought that [&] would do the same as listing all arguments one by one.
So what is going wrong here?
P.S:
This is not limited to -O3. -O0 does not segfault but does not return the expected result ("Hello World!"):
[:~/tmp] $ g++-6 -std=c++1z param.cpp && ./a.out
[:~/tmp] $
P.P.S: Further reduced SSCCE. Now I don't even get a diagnostic with -Wall -Wextra anymore.
I strongly suspect a g++ bug.
Here are some notes:
replacing std::string with any elementary type, e.g., int still does not work
clang and VC++ will work just as intended
not passing parameter pack by reference causes an internal compiler error with g++ 7.0.1 with the following output:
internal compiler error: in make_decl_rtl, at varasm.c:1304
...
Please
submit a full bug report, with preprocessed source if appropriate.
Please include the complete backtrace with any bug report. See
http://gcc.gnu.org/bugs.html for instructions.