I am using a sequence of string from this link: here
template<typename Char, Char... Cs>
struct char_sequence
{
static constexpr const Char c_str[] = {Cs..., 0};
};
// That template uses the extension
template<typename Char, Char... Cs>
constexpr auto operator"" _cs() -> char_sequence<Char, Cs...> {
return {};
}
Then, I would make a call :
call_lib("Test"_cs);
where
template<char... Cs>
void call_lib(char_sequence<char, Cs...> url){
const_str(url.c_str); // this gives an error
}
// a Class from library
class const_str{
const char* const begin_;
template<unsigned N>
constexpr const_str(const char (&arr)[N]):
begin_(arr);
{
}
}
The error when constructing the class const_str
error: no matching conversion for functional-style cast from 'const
char const[]' to 'const_str'
const_str(url.c_str);
The complainer then complains of no matching copy constructor or move constructor (This is expected since this is not the one we need for constructing it). However, the other note from the compiler is:
note: candidate template ignored: could not match 'const char' against 'const char'
which is referring to the template constructor template<unsigned N> constexpr const_str(const char (&arr)[N])
Why is the compiler saying that it could not match const char to const char. It sounds a bit counter intuitive.
How can I solve this problem without having to edit the class const_str
Once I fixed the many typos in your code (please don't post rubbish), the fix was simple enough.
Just change this:
constexpr auto operator"" _cs() -> char_sequence<Cs...> { ...
to this:
constexpr auto operator"" _cs() -> char_sequence<Char, Cs...> { ...
// ^^^^
and then it compiles.
Whether it does what you want or not is another thing. I didn't check that because I don't claim to understand it. And the code is specific to gcc, note, and fails to compile if you specify -pedantic-errors as many people here recommend.
Related
With the following program, which is an extract from something larger that I'm experimenting with, I get an error message that seems to be related to the constructor for fixed_string
#include <string>
#include <cstring>
template<std::size_t N>
struct fixed_string {
static const constexpr std::size_t size__ = N;
constexpr fixed_string(char const* s) :
buf("") {
for (std::size_t i = 0; i <= N; ++i)
buf[i] = s[i];
}
constexpr operator char const*() const {
return buf;
}
constexpr bool operator==(const char* other) const {
return ::strncmp(buf, other, N) == 0;
}
template<std::size_t M>
constexpr bool compare(const fixed_string<M>& other) const {
return (N == M && ::strncmp(buf, other.buf, N) == 0) ? std::true_type(): std::false_type();
}
char buf[N + 1];
};
template<std::size_t N>
fixed_string(char const (&)[N]) -> fixed_string<N - 1>;
////////////////////////////////////////////
template<fixed_string TARGET_NAME, fixed_string THIS_NAME>
concept NameMatches = (TARGET_NAME.compare(THIS_NAME));
template<fixed_string NAME, typename TYPE>
class Member {
public:
static const constexpr fixed_string name__ { NAME };
public:
template<fixed_string TARGET_NAME>
const TYPE& get() const requires NameMatches<TARGET_NAME, TYPE::name__> const {
return member_;
}
protected:
TYPE member_;
};
template<typename ... MEMBERS>
class Container: public MEMBERS... {
};
The error messages are:
../src/test-concepts.cpp:43:35: error: class template argument deduction failed:
43 | const TYPE& get() const requires NameMatches<TARGET_NAME, TYPE::name__> const {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/test-concepts.cpp:43:35: error: no matching function for call to ‘fixed_string(fixed_string<...auto...>)’
../src/test-concepts.cpp:8:12: note: candidate: ‘template<long unsigned int N> fixed_string(const char*)-> fixed_string<N>’
8 | constexpr fixed_string(char const* s) :
| ^~~~~~~~~~~~
../src/test-concepts.cpp:8:12: note: template argument deduction/substitution failed:
../src/test-concepts.cpp:43:35: note: couldn’t deduce template parameter ‘N’
43 | const TYPE& get() const requires NameMatches<TARGET_NAME, TYPE::name__> const {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/test-concepts.cpp:5:8: note: candidate: ‘template<long unsigned int N> fixed_string(fixed_string<N>)-> fixed_string<N>’
5 | struct fixed_string {
| ^~~~~~~~~~~~
../src/test-concepts.cpp:5:8: note: template argument deduction/substitution failed:
../src/test-concepts.cpp:43:35: note: mismatched types ‘fixed_string<N>’ and ‘fixed_string<...auto...>’
43 | const TYPE& get() const requires NameMatches<TARGET_NAME, TYPE::name__> const {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/test-concepts.cpp:28:1: note: candidate: ‘template<long unsigned int N> fixed_string(const char (&)[N])-> fixed_string<(N - 1)>’
28 | fixed_string(char const (&)[N]) -> fixed_string<N - 1>;
| ^~~~~~~~~~~~
../src/test-concepts.cpp:28:1: note: template argument deduction/substitution failed:
../src/test-concepts.cpp:43:35: note: mismatched types ‘const char [N]’ and ‘fixed_string<...auto...>’
43 | const TYPE& get() const requires NameMatches<TARGET_NAME, TYPE::name__> const {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/test-concepts.cpp:43: confused by earlier errors, bailing out
This is part of a project using templates that overloads a given function (get in this case), for which there is only one suitable candidate that fulfils the constraint. The value that the constraint operates on is a name - a string literal - not a const string variable, which is passed as a non-type parameter to an instantiation of the template: something like:
Container<Member<"fred", std::string>, Member<"bert", int>, Member<"alfie", bool>> some_values;
I want to be able to retrieve a value using something like
int result = some_values.get<"bert">();
I have had difficulty finding much information about the "<...auto...>" specialisation of the template. I presume this is an internal representation used by gcc for constant, non-type values.
The error messages point me to the lack of a suitable overloaded constructor for fixed_string. What should this be?
The problem I see is that fixed_string is a template class, not a class.
So, when you define a concept as
template<fixed_string TARGET_NAME, fixed_string THIS_NAME>
concept NameMatches = (TARGET_NAME.compare(THIS_NAME));
you have that fixed_string TARGET_NAME (fixed_string THIS_NAME also) doesn't works because fixed_string isn't a type. I mean: fixed_string<5> is a type, not fixed_string.
I know that you have a deduction guide that, given the literal string, deduce the template parameter for the fixed_string, but remain the problem that the concept should works with elements of different types (fixed_string of different lengths).
I suppose you can solve the problem with auto
template <auto TARGET_NAME, auto THIS_NAME>
concept NameMatches = (TARGET_NAME.compare(THIS_NAME));
but, when you declare Member, you have the same problem: fixed_string NAME doesn't works because fixed_sting (without a length) isn't a type.
template<fixed_string NAME, typename TYPE>
class Member
Unfortunately, if you use auto
template <auto NAME, typename TYPE>
class Member
defining a Member with a literal string argument (Member<"bert", int>, by example), nothing bring "bert" to a fixed_string.
Suggestion: what about a fixed_string without a template argument?
Here's a minimal example:
#include <iostream>
#include <type_traits>
template <typename T>
struct Foo {
typedef typename std::decay<T>::type U;
const U s;
Foo(const T& val): s(val) {}
};
template <typename T>
Foo<T> make_foo(const T& val) {
return Foo<T>(val);
}
int main() {
make_foo("foo");
}
I expect Foo::s (or U) to be const-ed, but the compiler error I'm getting (on Ubuntu WSL g++ 7.4.0) is
bar.cpp: In instantiation of ‘Foo<T>::Foo(const T&) [with T = char [4]]’:
bar.cpp:14:12: required from ‘Foo<T> make_foo(const T&) [with T = char [4]]’
bar.cpp:18:19: required from here
bar.cpp:9:28: error: invalid conversion from ‘const char*’ to ‘Foo<char [4]>::U {aka char*}’ [-fpermissive]
Foo(const T& val): s(val) {}
^
which obviously means that neither U or Foo::s is a const char*. Thoughts?
EDIT:
For anyone running into this problem, the solution is exactly as StoryTeller points out in his post below. In other words, the const I had in make_foo(const T& val) in the parameter signature was stripping the const from the type parameter and making T evaluate to char [4]. And for some reason, I couldn't even grasp putting a const in the template angle brackets of each instance of Foo<...> (the return type and the expression returned):
#include <iostream>
#include <type_traits>
template <typename T>
struct Foo {
static_assert(std::is_same<T, const char[4]>::value);
typedef typename std::decay<T>::type U;
static_assert(std::is_same<U, const char*>::value);
U s;
Foo(const T& val): s(val) {}
};
template <typename T>
Foo<const T> make_foo(const T& val) {
static_assert(std::is_same<T, char[4]>::value);
return Foo<const T>(val);
}
int main() {
make_foo("foo");
}
Also, as chris pointed out as well, it's nice to spam static_assert and std::is_same to make dealing with templates in combination with const a bit more sane.
make_foo accepts by a const T &, and you pass in a constant array of 4 characters (that's what string literals are). Template argument deduction must therefore match a const char (&)[4] against the const T &. And since the const is specified in the parameter type, that leaves T as char[4]. The const qualifier is "consumed" by the function parameter.
So when you instantiated Foo<T>, you did so with char[4]. That type will decay to a char*, not a const char*. Adding const on top of it will only produce a char * const.
If you wish to preserve the const-ness of T, then amend your return statement (and type) to be
return Foo<const T>(val);
How to make the following code compile?
template <typename C, size_t N>
constexpr uint64_t cs_hash(const C s[N])
{
return N;
}
constexpr char sample[] = "communism";
constexpr uint64_t h = cs_hash(sample);
The compiler error with MSVC 2017 is
error C2784: 'uint64_t cs_hash(const C [N])': could not deduce template argument for 'const C [N]' from 'const char [10]'
Use a const reference!
template <typename C, size_t N>
constexpr uint64_t cs_hash(const C (&s)[N])
{
return N;
}
Explanation
When you attempt to create a function parameter of type T [] or T [N], compiler automatically replaces the type with T *.
It means that your function declaration is no different from
template <typename C, size_t N>
constexpr uint64_t cs_hash(const C *s)
{
return N;
}
Since the parameter type doesn't depend on N, there is no way for N to be deduced.
But when you use a 'reference to array' parameter, said rule for array parameters doesn't apply, and nothing stops the deduction from working properly.
I have following implementation:
#include <cstddef>
template<typename Data, size_t Size>
class Demo
{
public:
Demo();
private:
Data data[Size];
};
void f(Demo<int, size_t>& demoObj)
{
}
int main()
{
Demo<int, 100> demoObj;
}
I get the following error when I compile:
g++ -std=c++11 temp.cpp
temp.cpp:13:24: error: type/value mismatch at argument 2 in template parameter list for ‘template<class Data, long unsigned int Size> class Demo’
void f(Demo<int, size_t>& demoObj)
^
temp.cpp:13:24: note: expected a constant of type ‘long unsigned int’, got ‘size_t {aka long unsigned int}’
The error is not making sense to me. Please help me understand it. Also, how do I pass demoObj to function f? I mean how o write the definition of f.
Size is a non-type parameter, so it requires a non-type argument:
void f(Demo<int, 100>& demoObj);
// ^^^
If you want to be able to pass in any kind of Demo you can define f as a template function.
template<typename Data, size_t Size>
void f(Demo<Data, Size>& demoObj)
{
// ...
}
The following code does not compile with GCC 5.2 (C++14). It does compile with clang 3.6 (C++14). (original code can be found here)
#include <cstddef>
#include <algorithm>
#include <type_traits>
#include <utility>
template <typename T>
class aggregate_wrapper;
template <typename T, std::size_t n>
class aggregate_wrapper<T[n]> {
public:
using array = T[n];
template <typename... Ts, typename = decltype(array{std::declval<Ts>()...})>
aggregate_wrapper(Ts&&... xs)
: arr_{std::forward<Ts>(xs)...} {
// nop
}
aggregate_wrapper(const array& arr) {
std::copy(arr, arr + n, arr_);
}
aggregate_wrapper(array&& arr) {
std::move(arr, arr + n, arr_);
}
operator T* () {
return arr_;
}
operator const T* () const {
return arr_;
}
constexpr std::size_t size() const {
return n;
}
private:
array arr_;
};
int main() {
aggregate_wrapper<int[3]> arr;
static_assert(arr.size() == 3, "");
}
The error message produced is
main.cpp: In function 'int main()':
main.cpp:44:3: error: non-constant condition for static assertion
static_assert(arr.size() == 3, "");
^
main.cpp:44:25: error: call to non-constexpr function 'constexpr std::size_t aggregate_wrapper<T [n]>::size() const [with T = int; long unsigned int n = 3ul; std::size_t = long unsigned int]'
static_assert(arr.size() == 3, "");
^
main.cpp:34:25: note: 'constexpr std::size_t aggregate_wrapper<T [n]>::size() const [with T = int; long unsigned int n = 3ul; std::size_t = long unsigned int]' is not usable as a constexpr function because:
constexpr std::size_t size() const {
^
main.cpp:34:25: error: enclosing class of constexpr non-static member function 'constexpr std::size_t aggregate_wrapper<T [n]>::size() const [with T = int; long unsigned int n = 3ul; std::size_t = long unsigned int]' is not a literal type
main.cpp:10:7: note: 'aggregate_wrapper<int [3]>' is not literal because:
class aggregate_wrapper<T[n]> {
^
main.cpp:10:7: note: 'aggregate_wrapper<int [3]>' is not an aggregate, does not have a trivial default constructor, and has no constexpr constructor that is not a copy or move constructor
Any ideas? Should the code compile according to the standard?
Or you could just make your existing variadic constructor serve as your constexpr constructor to perform the default construction:
template <typename... Ts, typename = decltype(array{std::declval<Ts>()...})>
constexpr // <---- ADD THIS
aggregate_wrapper(Ts&&... xs)
: arr_{std::forward<Ts>(xs)...} {
// nop
}
In order for g++ to get it compiled you will need to add a default constructor:
aggregate_wrapper() = default;
please see it in action at: http://coliru.stacked-crooked.com/a/df1ac057960bebc7
I have the feeling that clang under the hood added it, but I am not 100% sure ...
GCC is wrong. Its diagnostic, in part, says:
main.cpp:34:25: note: '<...>' is not usable as a constexpr function because:
main.cpp:34:25: error: enclosing class of constexpr non-static member function '<...>' is not a literal type
... but there is no such rule. See [dcl.constexpr]/3 for the list of constraints that apply here.
You can work around the bogus GCC diagnostic by adding a dummy constexpr constructor (it's fine for that constructor to be private and/or deleted if you don't want any of your real constructors to be constexpr) or by making size be static.