boost::hana::is_valid fails to compile with gcc8 (and more) and --std=c++14 - c++14

I use this code with std=c++14 and gcc7.3:
#include <iostream>
#include <string>
#include <type_traits>
#include <boost/hana/assert.hpp>
#include <boost/hana/equal.hpp>
#include <boost/hana/type.hpp>
namespace hana = boost::hana;
template<class T>
bool foo(T elem)
{
constexpr auto has_overload_to_string = hana::is_valid([](auto t) -> decltype(to_string(t)) {});
constexpr bool hasOverloadTo_string = has_overload_to_string(elem);
return hasOverloadTo_string;
}
int main()
{
std::string elem;
std::cin >> elem;
foo(elem);
}
And it works fine : demo
If now I use gcc10.1, I got this error: demo fail
prog.cc: In instantiation of 'bool foo(T) [with T = std::__cxx11::basic_string<char>]':
prog.cc:41:13: required from here
prog.cc:27:38: error: temporary of non-literal type 'foo<std::__cxx11::basic_string<char> >::<lambda(auto:1)>' in a constant expression
27 | [[maybe_unused]] constexpr auto has_overload_to_string =
| ^~~~~~~~~~~~~~~~~~~~~~
prog.cc:28:21: note: 'foo<std::__cxx11::basic_string<char> >::<lambda(auto:1)>' is not literal because:
28 | hana::is_valid([](auto t) -> decltype(to_string(t)) {});
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1plus: note: 'foo<std::__cxx11::basic_string<char> >::<lambda(auto:1)>' is a closure type, which is only literal in C++17 and later
My question is : Is gcc7.3 too permissive with C++14 and is_valid works when it shouldn't or gcc8 and more add a bug with C++14 ?

The error has nothing to do with hana::is_valid, but the lambda is not valid in a constant expression in C++14.
There is already a good language lawyer answer for this here:
https://stackoverflow.com/a/32697323/800347
Clang also consistently provides an error, so it's clear that previous versions of gcc were incorrect in allowing this.
To workaround this, simply remove the constexpr qualifier to your variable declaration.

Related

Compiler error in consecutive calls to constexpr functions

I've got the following example:
#include <cstdint>
template<typename T>
struct a_size {
constexpr static std::size_t size() { return sizeof(T); }
};
template<typename T>
constexpr std::size_t foo(T const& t) {
constexpr auto result = a_size<decltype(t)>::size();
return result;
}
template<typename T>
constexpr std::size_t bar(T const& t) {
constexpr auto result = foo(t);
return result;
}
int main() {
constexpr auto r = bar('c');
return r;
}
When compiling with g++ (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0 everything seems to be fine. But when I compile with clang++ (Version(s): clang version 10.0.0 (https://github.com/llvm-mirror/clang.git df2d9221d77042d6b07a6025edf9e810f1801ef5) (https://github.com/llvm-mirror/llvm.git a1e2fd38b595bd636661ac7416961e029c7e1689)) I've got the following error:
main.cc:16:33: error: constexpr variable 'result' must be initialized by a constant expression
constexpr auto result = foo(t);
~~~~^~
main.cc:21:24: note: in instantiation of function template specialization 'bar<char>' requested here
constexpr auto r = bar('c');
^
1 error generated.
I observe the similar behaviour on godbolt.org with clang 8.0.0 and clang trunk, the example is working, however, with GCC both 9.2.0 and trunk.
Compiled as
clang++ -std=c++17 main.cc -o main.run
g++ -std=c++17 main.cc -o main.run
Questions
Why is it so?
Why isn't constexpr-essness transitively applied/used (for lack of a better word) throughout the whole call-chain? (I understand that the result of the call to foo(t) is for some reason not marked constexpr. The question is about why.)
Which compiler is right?
What does the standard say?
Is it a bug? And if so, whether is it in GCC/G++ or in Clang?
Why removing a reference (&) in bar(T const&) solves the problem and clang no longer produces compilation error?
Edit (16.09.2019)
Obviously removing the intermediary result variable solves the problem (as suggested by David Ledger). But this does not answer the other questions. Not to mention that some use cases may require such an intermediary variable.

Boost Spirit accept rule dynamically when a keyword is used [duplicate]

Going by the opening paragraph of the boost::spirit::qi::symbols documentation, I assumed that it wouldn't be too hard to add symbols to a qi::symbols from a semantic action. Unfortunately it appears to be not as straightforward as I would have assumed.
The following bit of test code exhibits the problem:
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <string>
namespace qi = boost::spirit::qi;
typedef qi::symbols<char, unsigned int> constants_dictionary;
template <typename Iter> struct parser : public qi::grammar<Iter, qi::space_type> {
parser(constants_dictionary &dict) : parser::base_type(start) {
start = qi::lit("#") >> ((+qi::char_) >> qi::uint_)[dict.add(qi::_1, qi::_2)];
}
qi::rule<Iter> start;
};
int main() {
constants_dictionary dict;
parser<std::string::const_iterator> prsr(dict);
std::string test = "#foo 3";
parse(test.begin(), test.end(), prsr, qi::space);
}
Gives type errors related to qi::_2 from VS2010:
C:\Users\k\Coding\dashCompiler\spirit_test.cpp(12) : error C2664: 'const boost::
spirit::qi::symbols<Char,T>::adder &boost::spirit::qi::symbols<Char,T>::adder::o
perator ()<boost::spirit::_1_type>(const Str &,const T &) const' : cannot conver
t parameter 2 from 'const boost::spirit::_2_type' to 'const unsigned int &'
with
[
Char=char,
T=unsigned int,
Str=boost::spirit::_1_type
]
Reason: cannot convert from 'const boost::spirit::_2_type' to 'const uns
igned int'
No user-defined-conversion operator available that can perform this conv
ersion, or the operator cannot be called
C:\Users\k\Coding\dashCompiler\spirit_test.cpp(10) : while compiling cla
ss template member function 'parser<Iter>::parser(constants_dictionary &)'
with
[
Iter=std::_String_const_iterator<char,std::char_traits<char>,std::al
locator<char>>
]
C:\Users\k\Coding\dashCompiler\spirit_test.cpp(21) : see reference to cl
ass template instantiation 'parser<Iter>' being compiled
with
[
Iter=std::_String_const_iterator<char,std::char_traits<char>,std::al
locator<char>>
]
(Apologies for the nasty VS2010 error-style)
What syntax am I supposed to be using to add (and later on, remove) symbols from this table?
This question has been answered before. However, there is quite a range of problems with your posted code, so I'll fix them up one by one to spare you unnecessary staring at pages of error messages.
The working code (plus verification of output) is here on liveworkspace.org.
Notes:
the semantic action must be a Phoenix actor, i.e. you need
boost::bind, phoenix::bind, std::bind
phoenix::lambda<> or phoenix::function<>
a function pointer or polymorphic calleable object (as per the documentation)
I'd recommend phoenix::bind (in this particular case), which I show below
There was a mismatch between the parser's skipper and the start rule
qi::char_ eats all characters. Combined with the skipper, this resulted
in parse failure, because (obviously) the digits in the value were also being
eaten by +qi::char_. I show you one of many solutions, based on qi::lexeme[+qi::graph]
use qi::lexeme to 'bypass' the skipper (i.e. to prevent +qi::graph to cut
across whitespace because the skipper, well, skipped it)
qi::parse doesn't take a skipper; use qi::phrase_parse for that (the
reason it appeared to work is that any trailing 'variadic' arguments are
bound to the exposed attributes of the parser, which in this case are
unspecified, and therefore qi::unused_type).
if you want to pass test.begin() and test.end() directly to
qi::phrase_parse, you need to make it clear that you want const iterators. The
more typical solution would be to introduce explicitely typed variables
(first and last, e.g.)
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <string>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
typedef qi::symbols<char, unsigned int> constants_dictionary;
template <typename Iter> struct parser : qi::grammar<Iter, qi::space_type>
{
parser(constants_dictionary &dict) : parser::base_type(start)
{
start = qi::lit("#") >> (qi::lexeme [+qi::graph] >> qi::uint_)
[ phx::bind(dict.add, qi::_1, qi::_2) ]
;
}
qi::rule<Iter, qi::space_type> start;
};
int main() {
constants_dictionary dict;
parser<std::string::const_iterator> prsr(dict);
const std::string test = "#foo 3";
if (qi::phrase_parse(test.begin(), test.end(), prsr, qi::space))
{
std::cout << "check: " << dict.at("foo") << "\n";
}
}

Operating on thrust::complex types with thrust::transform

I'm trying to use thrust::transform to operate on vectors of type thrust:complex<float> without success. The following example blows up during compilation with several pages of errors.
#include <cuda.h>
#include <cuda_runtime.h>
#include <cufft.h>
#include <thrust/device_vector.h>
#include <thrust/host_vector.h>
#include <thrust/transform.h>
#include <thrust/complex.h>
int main(int argc, char *argv[]) {
thrust::device_vector< thrust::complex<float> > d_vec1(4);
thrust::device_vector<float> d_vec2(4);
thrust::fill(d_vec1.begin(), d_vec1.end(), thrust::complex<float>(1,1));
thrust::transform(d_vec1.begin(), d_vec1.end(), d_vec2.begin(), thrust::abs< thrust::complex<float> >() );
}
I'm using CUDA 8.0 on Ubuntu Xenial and compiling with clang 3.8.0-2ubuntu4 using nvcc --std=c++11 main.cpp -o main.
Main errors appear to be:
main.cpp: In function ‘int main(int, char**)’:
main.cpp:17:105: error: no matching function for call to ‘abs()’
gin(), d_vec1.end(), d_vec2.begin(), thrust::abs< thrust::complex<float> >() );
and
/usr/local/cuda-8.0/bin/../targets/x86_64-linux/include/thrust/detail/complex/arithmetic.h:143:20: note: template argument deduction/substitution failed:
main.cpp:17:105: note: candidate expects 1 argument, 0 provided
gin(), d_vec1.end(), d_vec2.begin(), thrust::abs< thrust::complex<float> >() );
^
No problem working on real floats, but no such with complex ones. I'm thinking there's a type error that I'm missing, but I'm very much still on the steep part of the learning curve with Thrust & templates.
The error message is quite descriptive:
thrust::abs<thrust::complex<...>> is a function which expects exactly one parameter, see thrust/detail/complex/arithmetic.h#L143:
template <typename ValueType>
__host__ __device__
inline ValueType abs(const complex<ValueType>& z){
return hypot(z.real(),z.imag());
}
For your use case, you need to wrap that function by a functor:
struct complex_abs_functor
{
template <typename ValueType>
__host__ __device__
ValueType operator()(const thrust::complex<ValueType>& z)
{
return thrust::abs(z);
}
};
Finally, employ that functor here:
thrust::transform(d_vec1.begin(),
d_vec1.end(),
d_vec2.begin(),
complex_abs_functor());

g++ fails to look up static functions in a template class, is it a bug or standard defined?

When I try some C++11 code like following, it passed in all clang++ available to me that support C++11, but it failed to compile in g++-4.8, g++-4.9 and g++-5.0.
#include <type_traits>
#include <vector>
template <class C, class First, class Last>
struct HasInsertEnd {
template <class U>
static std::false_type Check(...);
template <class U>
static auto Check(U val)
-> decltype(val.insert(val.end(), std::declval<First>(),
std::declval<Last>()),
std::true_type{});
template <class U>
using Deduce = decltype(Check<U>(std::declval<U>()));
using type = typename Deduce<C>::type;
static constexpr bool value = type::value;
};
int main(int argc, char* argv[]) {
static_assert(!HasInsertEnd<int, int, int>::value, "...");
static_assert(HasInsertEnd<std::vector<int>, const int*, const int*>::value,
"...");
return 0;
}
g++ will report errors like:
‘Check’ was not declared in this scope
If I change the calling of Check in the Deduce to HasInsertEnd::Check, both g++ and clang++ will be happy.
I know little about dependent name lookup. The problem is, which behavior is standard?
This is a bug in GCC, and can be shown to be a bug in GCC even without deferring to the standard.
template <typename T>
struct f { typedef int type; };
template <typename T>
struct S {
template <typename U>
static f<U> f();
template <class U>
using u = typename decltype(f<U>())::type;
using t = u<T>;
};
S<int>::t main() { }
This is rejected the same way in GCC 4.7.4 and GCC 5, with "error: ‘f’ was not declared in this scope". That's just nonsense. Even if the static member function should somehow not be visible, there is still a global type by the same name that would be found instead. It gets even better, though: with that global type, you get:
test.cc: In substitution of ‘template<class T> template<class U> using u = typename decltype (f<U>())::type [with U = T; T = T]’:
test.cc:12:20: required from here
test.cc:10:36: error: ‘f’ was not declared in this scope
using u = typename decltype(f<U>())::type;
^
test.cc:10:36: note: suggested alternative:
test.cc:2:12: note: ‘f’
struct f { typedef int type; };
^
test.cc:15:13: error: ‘t’ in ‘struct S<int>’ does not name a type
S<int>::t main() { }
^
That's right, it's suggesting that f can be corrected by spelling it f.
I don't see any problem with your code, and if it isn't a known bug, I encourage you to report it. and it's been reported as a bug before.
Oddly, as noted in the comments, GCC 4.8.4 and GCC 4.9.2 do find a global f. However, if the global f is a type, then they still reject the program, with "error: missing template arguments" even though the template argument is provided, so it's still clearly a bug in GCC.

Can we use parameter packs as std::vector initializers?

I'm experimenting with C++11 (I've used old C++ so far) and I wrote the following code:
#include <iostream>
#include <vector>
#include <type_traits>
using namespace std;
constexpr bool all_true(){
return true;
}
template <typename Head, typename... Tail>
constexpr bool all_true(Head head, Tail... tail){
static_assert( is_convertible<bool, Head>::value, "all_true arguments must be convertible to bool!");
return static_cast<bool>(head) && all_true(tail...);
}
template<typename T, typename... Args>
void print_as(Args... args){
static_assert( all_true(is_convertible<T,Args>::value...), "all arguments must be convertible to the specified type!");
vector<T> v {static_cast<T>(args)...};
for(T i : v) cout << i << endl;
}
int main(){
print_as<bool>(1, 2, 0, 4.1);
}
The code compiles and runs as expected (I used gcc 4.6). I would like to aks the following questions:
I initialized a std::vector with an expanded parameter pack ( vector v {static_cast(args)...}; ). Is this correct C++11? I haven't found this feature explained anywhere.
I don't like too much the declaration of all_true because I know the type but I use templates. Is it possible to use something similar to the following?
constexpr bool all_true(bool head, bool... tail){...} // This code doesn't compile
Thanks!
Yes, it is possible to use pack expansions inside initialiser lists. C++11 [temp.variadic]§4 allows this:
... Pack expansions can occur in the following contexts:
...
In an initializer-list (8.5); the pattern is an initializer-clause.
No, there's no way to make a non-template typesafe variadic function. What you have is OK. There was a question about this recently.

Resources