GCC produce "could not convert" error when using aggregate initialization - c++11

I'm trying to make C-string size calculation at compile time, using code like this:
#include <stdio.h>
#include <stdint.h>
class StringRef
{
public:
template<int N>
constexpr StringRef(const char (&str)[N])
: m_ptr(str), m_size(uint32_t(N-1)) {}
constexpr const char *constData() const
{ return m_ptr; }
private:
const char *m_ptr;
uint32_t m_size;
};
struct S
{
StringRef str;
};
constexpr static const struct S list[] =
{
"str",
};
int main()
{
printf("%s\n", list[0].str.constData());
return 0;
}
In clang-3.7 everything is fine, but in GCC 4.9.3-5.3 I get:
error: could not convert '(const char*)"str"' from 'const char*' to
'StringRef'
It can be fixed by adding explicit braces:
constexpr static const struct S list[] =
{{
{ "str" },
}};
But code became ugly and, still, clang somehow understand it correctly.
How can I make gcc understand array initialization without explicit braces?

Related

Error with calling a private constructor on macos

I am trying to port some C++ code that encodes the given data into base64 to macos. This is the a code sample from the same source which compiles and executes on godbolt but not on my mac:
#include <vector>
#include <string>
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/archive/iterators/insert_linebreaks.hpp>
using namespace boost::archive::iterators;
struct Encode
{
/// Sets the contents of an std::string to be used
/// as the input for the encoding operation.
/// \param a_Data The string to encode.
Encode(const std::string& a_Data);
/// Evaluates the expression and performs the base64 encoding.
/// \returns Base64 encoded string.
operator std::string() const;
private:
std::string Evaluate() const;
const char * m_Data;
size_t m_Size;
bool m_LineBreaks;
};
Encode::Encode(const std::string& a_Data)
: m_Data(a_Data.c_str())
, m_Size(a_Data.size())
, m_LineBreaks(false)
{
}
std::string Encode::Evaluate() const
{
typedef base64_from_binary<
transform_width<std::string::const_iterator,6,8>
> iterator;
typedef insert_linebreaks<iterator, 72> linebreak_iterator;
std::string base64;
if (m_LineBreaks) {
base64.assign(
linebreak_iterator(m_Data),
linebreak_iterator(m_Data + m_Size));
}
else {
base64.assign(
iterator(m_Data),
iterator(m_Data + m_Size));
}
return base64;
}
Encode::operator std::string() const
{
return Evaluate();
}
int main()
{
const std::string str64 = Encode("Hello World");
return 0;
}
I am compiling using g++:
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 10.0.0 (clang-1000.10.44.2)
Target: x86_64-apple-darwin17.7.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
However, there is the following error on line iterator(m_Data),:
boost/archive/iterators/transform_width.hpp:112:17: error: calling a private constructor of class 'std::__1::__wrap_iter<const char *>'
super_t(Base(static_cast< T >(start))),
^
<build_path>/boost/archive/iterators/base64_from_binary.hpp:91:13: note: in instantiation of function template specialization 'boost::archive::iterators::transform_width<std::__1::__wrap_iter<const char *>, 6, 8,
char>::transform_width<const char *>' requested here
Base(static_cast< T >(start)),
^
<src_path>/utilsBase64.cc:105:13: note: in instantiation of function template specialization 'boost::archive::iterators::base64_from_binary<boost::archive::iterators::transform_width<std::__1::__wrap_iter<const char *>, 6, 8, char>, char>::base64_from_binary<const
char *>' requested here
iterator(m_Data),
^
/Library/Developer/CommandLineTools/usr/include/c++/v1/iterator:1420:31: note: declared private here
_LIBCPP_INLINE_VISIBILITY __wrap_iter(iterator_type __x) _NOEXCEPT_DEBUG : __i(__x) {}
^
I have attempted to use clang++ and tried setting -stdlib=libc++ or stdlib=libstdc++ with a similar result. All examples of using the base64_from_binary shown in the code are similar to the given code sample.
One additional detail about m_Data, it is a member variable declared as: const char * m_Data;
Could someone please explain how this can be resolved?
Modifying the code to the following helped fix the issue:
std::string Encode::Evaluate() const
{
typedef base64_from_binary<
transform_width<std::string::const_iterator,6,8>
> iterator;
typedef insert_linebreaks<iterator, 72> linebreak_iterator;
std::string data(m_Data, m_Size);
std::string base64;
if (m_LineBreaks) {
base64.assign(
linebreak_iterator(data.begin()),
linebreak_iterator(data.end()));
}
else {
base64.assign(
iterator(data.begin()),
iterator(data.end()));
}
return base64;
}

Extract numeric parameters from template

I have following struct:
template <size_t INDEX_SIZE, size_t GENERATION_SIZE>
struct Handle
{
uint32_t index : INDEX_SIZE;
uint32_t generation : GENERATION_SIZE;
};
In code I declare a lot of type aliases like this:
using Object1Handle = Handle<12, 16>;
using Object2Handle = Handle<12, 16>;
...
I would like to have possibility to extract INDEX_SIZE and GENERATION_SIZE from alias. It can be macro, meta-template or function. For example:
constexpr size_t indexSize = ExtractIndexSize<Object1Handle>::IndexSize;
Is it possible?
Yes, that is possible. Using specialization:
template<class HandleInst>
struct ExtractIndexSize;
template<size_t index_size_, size_t generation_size_>
struct ExtractIndexSize<
Handle<index_size_, generation_size_>
> {
static constexpr size_t index_size = index_size_;
static constexpr size_t generation_size = generation_size_;
};
However, in this simple example (as also pointed out in the comments to your question) the static constexpr size_t could also be moved to Handle.
An alternative yielding "getter-like" syntax and fewer restrictions is
template<class HandleInst>
struct ExtractIndexSize;
template<size_t index_size_, size_t generation_size_>
struct ExtractIndexSize<
Handle<index_size_, generation_size_>
> {
static constexpr size_t index_size() { return index_size_; }
static constexpr size_t generation_size() { return generation_size_; }
};

How to make msvc 14 evaluate my constexpr at compile time

I am experimenting with c++ constexpr. I am implementing a HashedString class using FNV-1a hash.
Everything seems fine except that visual studio 2015 update 3 doesn't seem to evaluate the constexpr at compile time.
I added a static_assert and it shows no error, but in my test's disassembly it is clear that there is an explicit call to the constexpr function instead of the precomputed value.
I also tried with g++ and clang and they both are able to evaluate the constexpr at compile time.
Here is my test code:
#include <cstdint>
#include <cstddef>
#include <string>
class HashedString {
public:
//value working only for a 32bit hash
constexpr static size_t defaultOffset = 2166136261u;
constexpr static size_t prime = 16777619u;
/**
* Compute the hash of a string at compile time using FNV-1a hash
* https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80 %93Vo_hash_function
*/
template<std::size_t N>
constexpr HashedString(const char(&a)[N]) noexcept
: mHash(hash(a))
#if defined(_DEBUG)
, mString(a)
#endif
{
}
explicit constexpr HashedString(size_t h) noexcept : mHash(h) {}
constexpr static size_t hash(const char *const aString, const uint32_t val = defaultOffset) noexcept
{
return (aString[0] == '\0') ? val : hash(&aString[1], (val ^ uint32_t(aString[0])) * prime);
}
constexpr bool operator==(const HashedString & hs) const { return mHash == hs.mHash; }
constexpr bool operator==(const size_t & h) const { return mHash == h; }
constexpr bool operator!=(const HashedString & hs) const { return mHash != hs.mHash; }
constexpr bool operator!=(const size_t & h) const { return mHash != h; }
constexpr bool operator<(const HashedString & hs) const { return mHash < hs.mHash; }
private:
const size_t mHash = 0;
#if defined(_DEBUG)
const char* mString = nullptr;
#endif
};
static_assert(HashedString("FNV Hash Test") == 0xF38B3DB9, "HashedString of 'FNV Hash Test' shoulb be equal to 0xF38B3DB9");
int main(int , char**) {
constexpr HashedString hs("FNV Hash Test");
return hs == 0xF38B3DB9;
}
So my question is: Is there a way to make visual studio compute my constexpr at compile time?
Changing main to:
constexpr auto hash = HashedString::hash("FNV Hash Test");
return hash == 0xF38B3DB9;
or
constexpr HashedString hs("FNV Hash Test");
constexpr auto answer = hs == 0xF38B3DB9;
return answer;
will cause the hash to be computed at compile time. The way your code was there was no demand on the compiler to compute the hash at compile-time. By requiring the compiler to initialize a constexpr variable, it is forced to compute the value at compile-time. Which reduced main's code to:
mov eax,1
ret
Booyah! for VS2015's SSA optimizations.

Template specialization with constexpr non POD data initialization results in linker error when used in constructor as default value

Consider this:
struct TestStruct
{
uint16_t m_a : 8;
uint16_t m_b : 8;
};
template<typename T>
struct some_trait
{
constexpr static const TestStruct value = {0,0};
};
template<>
struct some_trait<int>
{
constexpr static const TestStruct value = {1,1};
};
template<class T>
class Obj
{
public:
Obj(TestStruct t = some_trait<T>::value) : m_t(t)
{
}
TestStruct m_t;
};
int main(int argc, const char * argv[])
{
// Linker error here -> Undefined symbol for some_trait<int>::value
Obj<int> o;
TestStruct t = some_trait<int>::value;
Obj<int> o1(t); // -> This works
}
The following produces a linker error, complaining that the some_trait is not defined. I have two questions:
Why is this happening? I'm guessing it has to do with either the constexpr specifier or the non-POD type of TestStruct ?
Is there a way to make it work, while still keeping the default value in the constructor?
Thanks!

Clang issue: Detecting constexpr function pointer with SFINAE

Based on the answer in Detecting constexpr with SFINAE I'm trying to use SFINAE to check if a 'constexpr' is present in my class.
The problem is that the constexpr is a function pointer:
#include <type_traits>
#include <iostream>
typedef int (*ptr_t)();
int bar() { return 9; }
struct Foo {
static constexpr ptr_t ptr = &bar;
};
namespace detail {
template <ptr_t>
struct sfinae_true : std::true_type {};
template <class T>
sfinae_true<T::ptr> check(int);
// Commented out to see why clang was not evaluating to true. This should only be
// a comment when debugging!
// template <class>
// std::false_type check(...);
} // detail::
template <class T>
struct has_constexpr_f : decltype(detail::check<T>(0)) {};
int main(int argc, char *argv[]) {
std::cout << has_constexpr_f<Foo>::value << std::endl;
return 0;
}
It seems to work fine using gcc, but clang complains:
test.cxx:23:39: error: no matching function for call to 'check'
struct has_constexpr_f : decltype(detail::check<T>(0)) {};
^~~~~~~~~~~~~~~~
test.cxx:26:22: note: in instantiation of template class 'has_constexpr_f<Foo>' requested here
std::cout << has_constexpr_f<Foo>::value << std::endl;
^
test.cxx:16:25: note: candidate template ignored: substitution failure [with T = Foo]: non-type template argument for template parameter of pointer type 'ptr_t' (aka 'int (*)()') must have its address taken
sfinae_true<T::ptr> check(int);
~ ^
1 error generated.
Q1: Can anyone suggest a way of doing this which works both for Clang and GCC?
Q2: Is this a bug in gcc, clang or is this left undefined in the c++ standard?
That's not a bug in clang, but an unfortunate restriction of arguments for non-type template parameters of pointer type (see pointer as non-type template argument). Essentially, you can only use arguments of the form &something: [temp.arg.nontype]/1 (from n3797)
[if the template-parameter is a pointer, its argument can be] a constant expression (5.19) that designates the address of a
complete object with static storage duration and external or
internal linkage or a function with external or internal linkage,
including function templates and function template-ids but excluding
non-static class members, expressed (ignoring parentheses) as &
id-expression, where the id-expression is the name of an object or
function, except that the & may be omitted if the name refers to a
function or array and shall be omitted if the corresponding
template-parameter is a reference; or [..]
[emphasis mine]
You can however, use a function pointer in a constant expression that has a non-pointer type, for example a boolean expression such as
T::ptr != nullptr
This works under clang++3.5 and g++4.8.2:
#include <type_traits>
#include <iostream>
typedef int (*ptr_t)();
int bar() { return 9; }
struct Foo0 {
static constexpr ptr_t ptr = &bar;
};
struct Foo1 {
static const ptr_t ptr;
};
ptr_t const Foo1::ptr = &bar;
struct Foo2 {
static const ptr_t ptr;
};
//ptr_t const Foo2::ptr = nullptr;
namespace detail
{
template <bool>
struct sfinae_true : std::true_type {};
template <class T>
sfinae_true<(T::ptr != nullptr)> check(int);
// the result of the comparison does not care
template <class>
std::false_type check(...);
} // detail::
template <class T>
struct has_constexpr_f : decltype(detail::check<T>(0)) {};
int main(int argc, char *argv[]) {
std::cout << std::boolalpha << has_constexpr_f<Foo0>::value << std::endl;
std::cout << std::boolalpha << has_constexpr_f<Foo1>::value << std::endl;
std::cout << std::boolalpha << has_constexpr_f<Foo2>::value << std::endl;
return 0;
}
Note there's a difference between clang++ and g++ for the second output (Foo1): g++ says true, clang++ says false.

Resources