template function taking array argument vs overload function taking pointer argument - c++

Consider the following code
#include <iostream>
#include <cstring>
template <int size>
void func(const char (&arr)[size])
{
//Prefer this function for const string literals.
std::cout << "Array of " << size - 1 << " bytes" << std::endl;
}
void func(const char *arr)
{
//Use this for all other strings that are not literals
std::cout << "String of " << strlen(arr) << " bytes" <<std::endl;
}
int main()
{
func("Hello!");
return 0;
}
How do I ensure that the template function is called in the example instead of the overload?
What I would like it that the templated function is called on string literals while the other is available for all other cases. With the templated function, i can avoid calling the strlen(). In my application both functions finally create a string_view object.
I would like to know how an overload is preferred.

The problem is that array-to-pointer conversions count as exact match rank when ranking standard conversion sequences during overload resolution. Since the array overload is a template the pointer overload thus becomes a better match.
You could add a proxy object for the pointer overload, to force it into a worse conversion sequence than that of the array overload for when the argument is of type const char (&)[N]:
namespace detail {
struct Proxy {
Proxy(const char *ptr) : ptr_{ptr} {};
operator const char *() const { return ptr_; }
private:
const char *ptr_;
};
} // namespace detail
template <int size> void func(const char (&arr)[size]) {
// Prefer this function for const string literals.
std::cout << "Array of " << size - 1 << " bytes" << std::endl;
}
void func(detail::Proxy const &proxy) {
// Use this for all other strings that are not literals
std::cout << "String of " << strlen(proxy) << " bytes" << std::endl;
}
int main() {
func("Hello!"); // Array of 6 bytes
const char *str = "Hello!";
func(str); // String of 6 bytes
}

The trick with a reference makes inexact match to const char* for a regular function.
#include <iostream>
#include <cstring>
template <size_t size>
void func(const char (&arr)[size])
{
//Prefer this function for const string literals.
std::cout << "Array of " << size - 1 << " bytes" << std::endl;
}
void func(const char *&arr)
{
//Use this for all other strings that are not literals
std::cout << "String of " << strlen(arr) << " bytes" <<std::endl;
}
int main()
{
func("Hello!");
const char *s = "s";
func(s);
return 0;
}
Output
Array of 6 bytes
String of 1 bytes

Related

How can I get C++ to prefer converting char* to string_view instead of bool?

I have a simple program like this:
#include <iostream>
#include <string_view>
class C {
public:
void print(std::string_view v) { std::cout << "string_view: " << v << std::endl; }
void print(bool b) { std::cout << "bool: " << b << std::endl; }
};
int main(int argc, char* argv[]) {
C c;
c.print("foo");
}
When I run it, it prints bool: 1
How can I get C++ to prefer the string_view implicit conversion instead of the bool implicit conversion?
You can turn the string_view overload into a template function, and add a constraint to it so that it has a higher preference than the bool overload when it receives a type that can be converted to string_view.
#include <string_view>
class C {
public:
template<class T>
std::enable_if_t<std::is_convertible_v<const T&, std::string_view>>
print(const T& v) { std::cout << "string_view: " << std::string_view(v) << std::endl; }
void print(bool b) { std::cout << "bool: " << b << std::endl; }
};
Demo.

C++ function overloading char called instead of double

I have a bunch of overloaded functions to take on specific int sizes, float, double, char and std::string.
eg:
#include <cstdint>
#include <iostream>
void some_func(uint8_t& src) {
std::cout << "inside uint8_t" << std::endl;
}
void some_func(uint16_t& src) {
std::cout << "inside uint16_t" << std::endl;
}
void some_func(uint32_t& src) {
std::cout << "inside uint32_t" << std::endl;
}
void some_func(uint64_t& src) {
std::cout << "inside uint64_t" << std::endl;
}
void some_func(bool& src) {
std::cout << "inside bool" << std::endl;
}
void some_func(double& src) {
std::cout << "inside double" << std::endl;
}
void some_func(float& src) {
std::cout << "inside float" << std::endl;
}
void some_func(const char& src) {
std::cout << "inside char" << std::endl;
}
int main() {
some_func((bool)true);
some_func((double)13.4);
return 0;
}
For some reason the overloaded const char& src function is called instead of double and bool. They both have explicit function overloads written, so why is the compiler promoting? moreover double is 64bits, so how is that being coverted to char? Can I solve this with template specialization? (I need to perform specifc actions depending on the data type)
Note: I am on Visual studio 2019 compiling with std=c++17
Non-const lvalue references can't be initialized with rvalues. (bool)true; and (double)3.14 are rvalues.
The only overload with a const lvalue reference parameter (which can be initialized with rvalues) is the const char& src one, that's why it's used.
Since the type is different (char vs bool/double), a temporary char is created from the argument, and then is bound to the reference.

How to get value type by C++ overload?

I'm confused about how to tell apart "lvalue" and "rvalue" in C, and "lvalue", "xvalue", "prvalue" in C++.
I'm thinking about getting the value type by overload in C++.
#include <iostream>
template<typename T>
void value_category(T & var)
{
std::cout << "Left Value" << std::endl;
}
template<typename T>
void value_category(T && var)
{
std::cout << "Right Value" << std::endl;
}
int main(void)
{
int arr1[4];
int arr2[4];
int arr3[4];
int * mat[3] = {arr1, arr2, arr3};
value_category(arr3);
value_category(arr2[3]);
value_category(mat);
value_category(mat[0]);
}
But it only tells whether lvalue or rvalue? Are there other solutions?

Why is there no to_string(const string&)?

I have template code which needs to convert some template type to string. For this I overload to_string for my own types. But the type can also be a string already. Then compilation fails, because there is no overload of to_string for type string itself (just returning its argument).
edit:
example code:
template<class T>
class TemplatedClass
{
public:
string toString() const
{
// this should work for both simple types like int, double, ...
// and for my own classes which have a to_string overload
// and also for string, which is the reason for my question
return string("TemplatedClass: ").append(to_string(t_));
}
private:
T t_;
};
You can just write your own templated function with proper overloads as follows:
#include <iostream>
#include <string>
using namespace std;
template<typename T>
std::string toString(const T& t) {
return std::to_string(t);
}
std::string toString(const char* t) {
return t;
}
std::string toString(const std::string& t) {
return t;
}
int main() {
cout << toString(10) << endl;
cout << toString(1.5) << endl;
cout << toString("char*") << endl;
cout << toString(std::string("string")) << endl;
return 0;
}
You can just combine all std::to_string and all your to_string by using derective. And pass std::string by value to minimize number of copies:
#include <string>
#include <iostream>
namespace convert {
std::string to_string(std::string s)
{
return s;
}
template<class T>
std::string stringify(T&& t)
{
using convert::to_string;
using std::to_string;
return to_string(std::forward<T>(t));
}
}
class Foo
{
public:
operator std::string () const { return "Foo"; }
};
namespace bar {
class Bar
{};
std::string to_string(const Bar&) {
return "Bar";
}
}
int main()
{
std::string s{"I'm lvalue string"};
std::cout << convert::stringify(42) << "\n";
std::cout << convert::stringify(std::string("I'm string")) << "\n";
std::cout << convert::stringify("I'm c-string") << "\n";
std::cout << convert::stringify(s) << "\n";
std::cout << convert::stringify(Foo{}) << "\n";
std::cout << convert::stringify(bar::Bar{}) << "\n";
return 0;
}
Note that with my approach you don't need an overload for const char * or any other type that is convertible to a string. Also this approach allows a user to add to_string overload for any class (it will be found by argument-dependent lookup).
For further optimization convert::to_string accepting a string by value can be split into lvalue and rvalue overloads.
Since C++17 you can use constexpr in if statements.
You can use it as follows:
#include <iostream>
#include <string>
template<typename Ty>
std::string ToString(const Ty& value) {
if constexpr (std::is_convertible_v<Ty, std::string>) {
return value;
}
else {
return std::to_string(value);
}
}
int main() {
std::cout << ToString(123) << std::endl;
std::cout << ToString(123.0) << std::endl;
std::cout << ToString("char*") << std::endl;
std::cout << ToString(std::string("std::string")) << std::endl;
return 0;
}

Printing out value of variable of unknown type?

I'm trying to write a simple function template in C++ in which I am printing out the value of a variable of unknown type. The problem is I can't figure out how to do this since the variable could either be a pointer or a primitive type. With the primitive type, I can simply print the value out; but pointers require de-referencing.
The following code gives me an error:
#include <iostream>
#include <type_traits>
using namespace std;
template<typename T>
void foo(T someVar) {
if(std::is_fundamental<T>::value) {
cout << "It's primitive! \n" << someVar << endl;
} else {
cout << "It's a pointer! \n" << *someVar << endl;
}
}
int main(int argc, char **argv) {
int x = 5;
foo(x);
int *y = new int();
*y = 5;
foo(y);
delete y;
return 0;
}
The error I get when I compile is:
test.cc: In function 'void foo(T) [with T = int]':
test.cc:19:8: instantiated from here
test.cc:13:5: error: invalid type argument of unary '*' (have 'int')
It's complaining that I'm trying to de-reference a primitive type from my first call to foo(), but that's exactly why I'm using the if-statement: to check if it's primitive or not. How would I go about implementing what I'm trying to do?
What you need to do, is write 2 versions of your templated function.
template<typename T>
void foo(T someVar) {
cout << "Assume it's primitive! \n" << someVar << endl;
}
template<typename T>
void foo(T* pVar) {
cout << "This is a pointer! \n" << *pVar << endl;
}
The compiler will choose the pointer version if it works, because it's more specific. If the type is not a (raw) pointer, it will default to the first version.
If you need smart pointers to be dereferenced, you can further overload your function definition.
Eg.
template<typename T>
void foo(std::shared_ptr<T> pVar) {
cout << "This is a shared pointer! \n" << *pVar << endl;
}
You need an additional layer of indirection.
#include <iostream>
template < typename T >
struct print_helper
{
static void
print(std::ostream& os, const T& value)
{
os << "The value is " << value << "\n";
}
};
template < typename T >
struct print_helper< T * >
{
static void
print(std::ostream& os, const T *const pointer)
{
os << "The pointer points to " << *pointer << "\n";
}
};
template < typename T >
void
foo(T whatever)
{
print_helper<T>::print(std::cout, whatever);
}
int
main()
{
const auto a = 42;
foo(a);
foo(&a);
}
Output:
The value is 42
The pointer points to 42
A solution I'm partial to for just printing nicely is to write a function to do the dereferencing.
template<typename T> T &deref(T &elem) { return elem; }
template<typename T> T &deref(T *elem) { return *elem; }
Then you can simply use deref(value) anywhere you don't know whether or not value will be a pointer, as long as you don't care which it is.
template<typename T>
void print(T t) {
std::cout << deref(t) << '\n';
}
Write the function twice:
struct Foo
{
template<typename T>
static void foo(T val) {
cout << "var: " << val << endl;
}
template<typename T>
static void foo(T* val) {
cout << "ptr: " << *val << endl;
}
};
To call:
int x;
int *y;
Foo::foo(x);
Foo::foo(y);