Could not deduce template argument with std::basic_string - c++

The striped-down version of my problem:
I want to merge these two functions:
void Bar(const std::string &s);
void Bar(const std::wstring &s);
..into one templated function:
template <class CharType>
void Foo(const std::basic_string<CharType> &s);
And I thought I will be be able to call Foo like (1) and (2), but to my surprise not even (3) works.
(1) Foo("my string");
(2) Foo(std::string("my string"));
(3) Foo(std::basic_string<char>("my string"));
I tried removing the const qualifier for parameter s and even dropping the reference (&), or calling with lvalues instead of rvalues, but all with the same result.
The compiler (both gcc and VS - so I am pretty sure it's a standard compliant behaviour) can't deduce the template argument for Foo. Of course it works if I call Foo like Foo<char>(...).
So I would like to understand why this is, especially since the call (3) is a one-to-one type between the type of the calling parameter object and the function argument type.
Secondly, I would like a workaround to this: to be able to use one templated function, and to be able to call it like (1) and (2).
Edit
(2) and (3) do work. I was declaring it wrong in my compiler (not like in my question):
template <class CharType>
void Foo(const std::basic_string<char> &s);
Sorry about that.

1) won't work because you're trying to use a const char[10] instead of a std::string
2) should work and so should 3) since default template parameters should ensure you're using defaults
#include <iostream>
using namespace std;
template <class CharType>
void Foo(const std::basic_string<CharType> &s)
{
cout << s.c_str(); // TODO: Handle cout for wstring!!!
}
void Foo(const char *s)
{
Foo((std::string)s);
}
int main()
{
std::wstring mystr(L"hello");
Foo(mystr);
Foo("world");
Foo(std::string("Im"));
Foo(std::basic_string<char>("so happy"));
return 0;
}
http://ideone.com/L63Gkn
Careful when dealing with template parameters. I also provided a small overload for wstring, see if that fits you.

Related

how to handle variadic template functions as class constructor and class members

I hope you are doing great.
I have a class for which I wants its constructor to take an undefined number of arguments, then I though about variadic template.
I can instantiate objects using constructor with no parameters and also with just one parameters, but when I try to use a constructor with two parameters, I get a compile time error like:
error: no matching function for call to 'pinBase::init(GPIO_TypeDef* const&, const long unsigned int&)'
pinBase(const Args& ...rest){init(<----MARKS ERROR HERE--->rest...);}
This is how I conceived my class:
//pinBase.hh
class pinBase
{
private:
GPIO_TypeDef *_instance;
GPIO_PIN _pin = PIN[0];
GPIO_MODE _mode = INPUT;
//these are the functions to which each individual expansion should be called
void _init();
void _init(GPIO_TypeDef* GPIOx);
void _init(GPIO_PIN pin);
//one of these two functions gets called by the constructor either with void or param of certain type
void init(){_init();}
template <class T>
void init(T t){_init(t);}
public:
//constructor accepts void or multiple params ( ... can be empty)
template <class ...Args>
pinBase(const Args& ...rest){init(rest...);}
~pinBase();
}
This is my implementation file:
//pinBase.cpp
#include "pinBase.hh"
pinBase::~pinBase()
{
}
void pinBase::_init()
{
uint8_t temp = 124; // I have set breakpoint here
}
void pinBase::_init(GPIO_TypeDef* GPIOx)
{
_resetValues = *GPIOx; // I have set breakpoint here
}
void pinBase::_init(GPIO_PIN pin)
{
_pin = pin; // I have set breakpoint here
}
This is main file:
//main.cpp
#include "stdint.h"
#include "pinBase.hh"
pinBase pin; //works perfect
pinBase otropin(GPIOA);//works perfect
pinBase andererpin(PIN_0);//works perfect
/**When commented,the program runs well
*and gets to each of the breakpoints
*with no problems at all.
**when uncommented, causes compile time error.
*/
pinBase anotherpin(GPIOA, PIN_0);
int main(void)
{
while (1)
{
/* code */
}
return 0;
}
You clarified that you expect a single call to init() for each variadic parameter.
What you are looking for is a fold expression (requires a C++17 compiler, or later):
template <class ...Args>
pinBase(const Args& ...rest){ (init(rest), ...);}
The syntax you're using results in a single call to init(), with all parameters forwarded in the single function call. The parameter pack gets expanded into a single, forwarded, parameter pack.
A fold expression, on the other hand, should produce your expected result (and you should not need an init() overload with no parameters).
The problem is not with the constructor itself but with the method pinBase::init. In particular, pinBase::init has only 1 parameter so you cannot call it with 2 or more arguments. That is, when you wrote:
init(rest...)
In the above, you're calling pinBase::init by passing all the arguments that the parameter pack has. But since init currently only has one parameter of type T, it cannot be called with 2 or more arguments.
To solve this you can make init a variadic as well as shown below:
class pinBase
{
private:
//------------vvvvvvvv------------->T is a template parameter pack
template <class... T>
//-------------vvv----------------->t is a function parameter pack
void init(T... t){}
//other code here as before
};
Working demo

How to explicitly call the specified overload function?

#include <cstdio>
#include <string>
constexpr char str[] = "/home/qspace/etc/client/mmkvcfgsvr_test_byset_cli.conf";
void test(bool a)
{
printf("b=%d",a);
}
void test(const std::string& s){
printf("s=%s",s.c_str());
}
int main()
{
test(str);
return 0;
}
Like this code, the C++ compiler will convert char* to bool and then call the first function, which is inconsistent with my original intention.
Is there any way to prevent the compiler from performing type conversions that I don't want?
Like "-fno-permissive", but unfortunately, it doesn't work.
How to explicitly call the specified overload function?
Convert the argument at call site: test(std::string(str));
Take expected address of overload function: static_cast<void(*)(const std::string&)>(print)(str);
Is there any way to prevent the compiler from performing type conversions that I don't want?
You might add a catch-all overload as deleted: template <typename T> void test(const T&) = delete;
Alternatively, in C++17, you might do the "dispatching" manually:
template <typename T>
void test(const T& t)
{
static_assert(std::is_constructible_v<std::string, T>
|| std::is_convertible_v<T, bool>);
if constexpr (std::is_constructible_v<std::string, T>) {
const std::string& s = t;
printf("s=%s", s.c_str());
} else if constexpr (std::is_convertible_v<T, bool>) {
printf("b=%d", bool(t));
}
}
You're mixing C and STL types (char array vs std::string). There are two solutions. The immediately obvious solution is to create a temporary std::string object every time you wish to pass a char array into a function expecting std::string.
test(std::string(str));
The other solution, which I prefer, is to avoid C types altogether. To create a string constant, use STL type directly:
const std::string str {"/home/qspace/etc/client/mmkvcfgsvr_test_byset_cli.conf"};
If you wish to retain constexpr see this thread: Is it possible to use std::string in a constexpr?

How do I force conversion char[] to char* in template instantiation?

Let's say I have a function:
#include <optional>
template <typename T>
std::optional<T> foo(T const &input);
It accepts a value, attempts to work with a copy of it and returns said copy on success (std::nullopt on fail).
But the problem is, when a string literal is passed into such function, an error T in optional<T> must meet the Cpp17Destructible requirements occurs.
It's caused by static_assert(is_object_v<_Ty> && is_destructible_v<_Ty> && !is_array_v<_Ty>, ...) defined in <optional>.
The next expression works correctly:
foo((char const*) "bar");
This one fails:
foo("bar");
The question is, how do I force the compiler to implicitly convert char const[] to char const*?
P. S. I know that it could be done by simply overloading the function, by I'm not too keen on code duplication it causes, so I'm curious whether an alternative solution is applicable here.
Edit: Rewrote the answer. With return type deduction, this would be convenient.
template <typename T>
auto foo(T const &input){
auto copy {std::move(input)};
// ...
return std::optional{std::move(copy)};
}
Not really what you asked for, though consider that not much repetition is needed:
template <int s>
std::optional<const char*> foo(const char (&str)[s]) {
return foo(&str[0]);
}
or simpler:
std::optional<char const*> foo(char const *input) {
return foo<char const *>(input);
}

Deducing a const l-value reference from a non-const l-value reference in C++ template

Suppose you have the following pair of functions:
void f(const int&) {
// Do something, making a copy of the argument.
}
void f(int&&) {
// Do the same thing, but moving the argument.
}
They are fairly redundant—the only difference between the functions being whether they copy or move their argument. Of course, we can do better by re-writing this as a single template function:
template<typename T>
void g(T&&) {
// Do something, possibly using std::forward to copy or move the argument.
}
This works, and is a commonly used idiom in practice. But the template might be instantiated into three functions, up from our two above. We can verify this occurs with the following piece of code:
#include <iostream>
template<typename T> constexpr char *type = nullptr;
template<> constexpr const char *type<int&> = "int&";
template<> constexpr const char *type<const int&> = "const int&";
template<> constexpr const char *type<int> = "int";
template<typename T>
void g(T&&) {
std::cout << reinterpret_cast<void*>(&g<T>)
<< " = &g<" << type<T> << ">" << std::endl;
}
int main() {
int i = 0;
const int& cr = 0;
g(i);
g(cr);
g(0);
return 0;
}
/*
Prints:
0x100f45080 = &g<int&>
0x100f45100 = &g<const int&>
0x100f45180 = &g<int>
*/
This has added a third function for the case when T = int&, which we didn't have when we were using our non-templated function f above. In this case, we don't actually need this non-const l-value reference version of the function—given f was sufficient for our original needs—and this increases the size of our code, especially if we have many template functions written this way that call each other.
Is there a way to write our function g above so that the compiler will automatically deduce T = const int& when g(i) is called in our example code? I.e., a way where we don't have to manually write g<const int&>(i) yet still get the desired behavior.
It is a subjective point-of-view to say "forward references" ("universal references") are better than dedicated overloads. There are certainly many cases where this is true, but if you want to have full control they won't do all the jobs.
You could explicitly make sure users do not pass non-const lvalue references, by adding
static_assert(!std::is_lvalue_reference<T>::value || std::is_const<typename std::remove_reference<T>::type>::value, "only call g with const argument");
inside g, but this is not in all cases a very good solution.
Or you do what is done for vector::push_back(...) and provide explicit overloads -- but this was your starting point, see https://en.cppreference.com/w/cpp/container/vector/push_back.
The 'correct' answer just depends on your requirements.
Edit:
the suggestion of #Sjoerd would look something like:
template <typename T>
class aBitComplicated {
public:
void func(T&& v) { internal_func(std::forward<T>(v)); }
void func(const T& v) { internal_func(v); }
private:
template <typename U>
void internal_func(U&& v) { /* your universal code*/ }
};
There also a bit more sophisticated/complicated version of this, but this here should be the most simple version to achieve what you asked for.

Which of two overloaded templates will be called?

I am still trying to figure out templates. I have read about the specialization rules and don't understand what is happening here.
I have defined the following in templates.h:
#include <iostream>
template <typename foo>
void f(foo p)
{
std::cout << "one" << std::endl;
}
template <typename bar>
void f(int p)
{
std::cout << "two" << std::endl;
}
Now if I include this and call it in my main like this
f(1);
f("x");
I get
one
one
Now the questions is, why is the first more specific than the second for ints? I feel like it should at least be ambiguous and not work at all.
First off, you don't have specializations, but two separate, unrelated overloads.
Secondly, the second overload is trivially non-viable, since you call the function without template arguments, and thus there is no way to deduce the template parameter bar. So only the first overload is viable, and gets used.
An actual specialization would look like this:
template <>
void f<int>(int p) { /* ... */ }
Better yet, stick with overloads (it's generally better to overload functions than to provide template specializations), but make the second one a non-template:
void f(int p) { /* ... */ }
The second overload one has no template dependency on function arguments, so you would have to call it like this:
f<std::string>(1);
f<double>(42);
f<SomeType>(1);
Whether it makes sense to have the second version is a different matter. You could imagine having a template parameter that does have some effect on the internal logic of the function:
template <typename SomeType>
int foo(int seed) {
// instantiate a SomeType and use it to calculate return value
};
int i = foo<Type1>(42);
int j = foo<Type2>(42);
On the other hand, your SomeType could be a function parameter:
template <typename SomeType>
int foo(int seed, const SomeType& s) {
// use s to calculate return value
};
Type1 t1;
Type2 t2;
int i = foo(42, t1);
int j = foo(42, t2);
In the second one bar cannot be deduced from function arguments, and must be given explicitly:
f<whatever>(1);
The one, which prints "two" is not recognized as explicit specialization. Try thisL
template <>
void f(int p)
{
std::cout << "two" << std::endl;
}