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?
Related
I'm trying to write a static variadic templates constructor for my class. But I'm not so experienced in variadic templates and get an error.
I wrote the following code:
template <typename T> struct scalar {
template <typename... Args> static std::shared_ptr<scalar<T>> create(Args &&...args) {
return std::make_shared<scalar<T>>((std::forward<Args>(args))...);
}
};
template <typename T>
std::shared_ptr<scalar<T>> operator+(std::shared_ptr<scalar<T>> &lhs,
std::shared_ptr<scalar<T>> &rhs) {
auto res = scalar<T>::create(lhs->data + rhs->data, {lhs, rhs}, "+");
res->backward = [lhs, rhs, res]() {
lhs->grad += res->grad;
rhs->grad += res->grad;
};
return res;
}
and I got that error:
error: no matching function for call to ‘red_engine::scalar<double>::create(red_engine::scalar<double>::value_type, <brace-enclosed initializer list>, const char [2])’
143 | auto res = scalar<T>::create(lhs->data * rhs->data, {lhs, rhs}, "*");
| ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/alex/projects/AI/nanograd/nanograd-cpp/engine.hpp:36:46: note: candidate: ‘static red_engine::scalar<T>::pointer red_engine::scalar<T>::create(Args&& ...) [with Args = {}; T = double; pointer = std::shared_ptr<red_engine::scalar<double> >]’
36 | template <typename... Args> static pointer create(Args &&...args) {
| ^~~~~~
/home/alex/projects/AI/nanograd/nanograd-cpp/engine.hpp:36:46: note: candidate expects 0 arguments, 3 provided
Can someone explain me what am I doing wrong?
Thank you in advance!
{lhs, rhs} doesn't have a type, so the respective type in Args... can't be deduced, and it seems to make the compiler assume Args is empty, hence candidate expects 0 arguments.
Use something that does have a type, like MyClass{lhs, rhs} or MyClass(lhs, rhs).
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.
I'm trying to insert an enum parameter into a constexpr function. I have done this in the past and it always worked... except in this case. This case is only special in that I'm calling a factory function first. But apparently C++ doesn't see through this. What can be done?
Those are my errors:
<source>: In function 'constexpr auto operator+(some_enum)':
<source>:30:28: error: no matching function for call to 'signal<1, state>(std::nullptr_t)'
30 | return signal<1, state>(nullptr);
| ~~~~~~~~~~~~~~~~^~~~~~~~~
<source>:23:37: note: candidate: 'template<bool set, some_enum S, class ... Ts> constexpr signal_str<sizeof... (Ts)> signal(Ts ...)'
23 | constexpr signal_str<sizeof...(Ts)> signal(Ts... Args)
| ^~~~~~
<source>:23:37: note: template argument deduction/substitution failed:
<source>:30:28: error: 'state' is not a constant expression
30 | return signal<1, state>(nullptr);
| ~~~~~~~~~~~~~~~~^~~~~~~~~
<source>:30:28: note: in template argument for type 'some_enum'
<source>:28:16: error: invalid return type 'auto' of 'constexpr' function 'constexpr auto operator+(some_enum)'
28 | constexpr auto operator+(some_enum state)
| ^~~~~~~~
Compiler returned: 1
This is my code:
#include <array>
#include <cstdint>
#include <iostream>
typedef void* TaskType_t;
enum some_enum
{
SOME_STATE = 1,
};
template <size_t N>
struct signal_str
{
uint32_t val_;
std::array<TaskType_t, N> tasks_;
};
template <bool set, some_enum S, typename... Ts>
constexpr signal_str<sizeof...(Ts)> signal(Ts... Args)
{
return signal_str<sizeof...(Ts)>{S, {Args...}}.val_;
}
constexpr auto operator+(some_enum state)
{
return signal<1, state>(nullptr);
}
int main()
{
static_assert(+SOME_STATE);
}
I'm using C++17 on xtensa-gcc 8.2.0 but it's the same with gcc 11 (LIVE DEMO).
EDIT: This problem is different from "Why is const variable necessary for template specialization over constants" because enums are already constants. To showcase this the following DOES actually compile:
#include <array>
#include <cstdint>
#include <iostream>
typedef void* TaskType_t;
enum some_enum
{
SOME_STATE = 1,
};
template <size_t N>
struct signal_str
{
uint32_t val_;
std::array<TaskType_t, N> tasks_;
};
constexpr auto operator+(some_enum state)
{
return signal_str<1>{state, nullptr}.val_;
}
int main()
{
static_assert(+SOME_STATE);
}
DEMO
So the problem IMHO is not the enum..
I am confused on how to use this method. I tried the following:
std::equal_to(T objA, T objB);
I get errors if I use it like this. However, I have seen countless examples that use it like this:
pairs1 = mismatch(v1.begin(), v1.end(),
v2.begin(),
equal_to<int>());
How is this method supposed to be used?
Sample Error:
prog.cpp: In function ‘int main()’:
prog.cpp:25:31: error: no matching function for call to ‘std::equal_to<int>::equal_to(std::vector<int>&, std::vector<int>&)’
pairs1 = equal_to<int>(v2, v1));
^
In file included from /usr/include/c++/5/string:48:0,
from /usr/include/c++/5/random:40,
from /usr/include/c++/5/bits/stl_algo.h:66,
from /usr/include/c++/5/algorithm:62,
from prog.cpp:2:
/usr/include/c++/5/bits/stl_function.h:352:12: note: candidate: constexpr std::equal_to<int>::equal_to()
struct equal_to : public binary_function<_Tp, _Tp, bool>
^
/usr/include/c++/5/bits/stl_function.h:352:12: note: candidate expects 0 arguments, 2 provided
/usr/include/c++/5/bits/stl_function.h:352:12: note: candidate: constexpr std::equal_to<int>::equal_to(const std::equal_to<int>&)
/usr/include/c++/5/bits/stl_function.h:352:12: note: candidate expects 1 argument, 2 provided
/usr/include/c++/5/bits/stl_function.h:352:12: note: candidate: constexpr std::equal_to<int>::equal_to(std::equal_to<int>&&)
/usr/include/c++/5/bits/stl_function.h:352:12: note: candidate expects 1 argument, 2 provided
equal_to is not a function, you cannot call it directly like one. It's a class that has the operator() defined which means that you need to create an object and call operator() on that object.
Possible implementation:
template <class T = void>
struct equal_to {
constexpr bool operator()(const T& lhs, const T& rhs) const
{
return lhs == rhs;
}
};
Usage example:
auto test()
{
auto my_comp = equal_to<int>{};
bool b1 = my_comp(2, 3);
// or create a temporary object and call it in one line:
bool b2 = equal_to<int>{}(2, 3);
}
It also has a specialization that will deduce the arguments passed to operator():
template <>
struct equal_to<void> {
template <class T, class U>
constexpr auto operator()(T&& lhs, U&& rhs) const
-> decltype(std::forward<T>(lhs) == std::forward<U>(rhs))
{
return std::forward<T>(lhs) == std::forward<U>(rhs);
}
};
auto test2()
{
using namespace std::string_literals;
auto my_comp = equal_to<>{};
bool b1 = my_comp(2, 3);
bool b2 = my_comp("one string"s, "another string"s);
}
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);