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
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;
}
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_; }
};
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.
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!
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.