Auto convert const char[] to const char * in template function - c++

I'm having problems with templates whereby if you try and give a templated function a string argument, the compiler interprets "Hello World" as const char [12]. I would like it to be const char *.
I can 'work around' the problem by static casting each string to 'const char*', but since I'm trying to use this as part of a logging system, making it simple is a big goal.
Since its difficult to explain what i mean, i have come up with a simple reproducer. You will see that the last line of the main function doesn't compile.
Any help would be greatly appreciated
#include <string>
// Trivial base class so we can use polymorphism
class StoreItemsBase
{
public:
StoreItemsBase() {}
};
// Example of a trivial Templated class to hold some 3 items.
// Intent to have similar classes to hold 4,5..n items
template <typename T1, typename T2, typename T3>
class Store3Items : public StoreItemsBase
{
public:
Store3Items(const T1& t1, const T2& t2, const T3& t3)
:
StoreItemsBase(),
mT1(t1),
mT2(t2),
mT3(t3)
{}
private:
T1 mT1;
T2 mT2;
T3 mT3;
};
// Function to create a pointer to our object with added id
// There would be similar CreateHolderFunctions for 4,5..n items
template <typename T1, typename T2, typename T3>
StoreItemsBase* CreateHolder(const T1& t1, const T2& t2, const T3& t3)
{
return new Store3Items<T1, T2, T3>(t1, t2, t3);
}
int main()
{
int testInt=3;
double testDouble=23.4;
const std::string testStr("Hello World");
StoreItemsBase* Ok1 = CreateHolder(testInt, testDouble, testStr);
StoreItemsBase* Ok2 = CreateHolder(testDouble, testStr, testInt);
StoreItemsBase* Ok3 = CreateHolder(testStr, static_cast<const char*>("Hello there"), testInt);
// If you try a standard string, it compiler complains
// Although I could surround all my strings with the static cast, what I am looking for is a way
// to for the CreateHolder function to do the work for me
StoreItemsBase* NotOk4 = CreateHolder(testStr, "Hello World", testInt);
// Free our objects not shown in the example
}
Compiler error is:
example.cpp: In constructor ‘Store3Items::Store3Items(const T1&, const T2&, const T3&) [with T1 = std::basic_string, T2 = char [12], T3 = int]’:
example.cpp:50:50: instantiated from ‘StoreItemsBase* CreateHolder(const T1&, const T2&, const T3&) [with T1 = std::basic_string, T2 = char [12], T3 = int]’
example.cpp:65:74: instantiated from here
example.cpp:21:11: error: array used as initializer

You could use a metafunction to transform the types passed as argument to your templates. Any array of chars would be transformed into a char*:
template< typename T > struct transform
{
typedef T type;
};
template< std::size_t N > struct transform< char[N] >
{
typedef char* type;
};
template< std::size_t N > struct transform< const char[N] >
{
typedef const char* type;
};
Then, instead of using Tn directly you would use typename transform< Tn >::type.
Update: If you are working in C++11, then std::decay already does what you want.

Try changing the template arguments to const T1 t1, const T2 t2, const T3 t3. It will be less performant but it compiles
Deciding on function arguments based on template arguments is often difficult. You can try this for the class constructor signature. I used template specialization of the class "arg_type" (non-standard) to make sure all arguments types that are not const pointers are passed by const ref and all const pointers are passed as const pointers.
Also, don't forget the virtual destructor on your base class or bad things might happen :)
#include <string>
// Trivial base class so we can use polymorphism
class StoreItemsBase
{
public:
StoreItemsBase() {}
virtual ~StoreItemsBase() {}
};
template <typename TYPE> class arg_type
{
public:
typedef const TYPE& type;
};
template <typename TYPE> class arg_type<const TYPE*>
{
public:
typedef const TYPE* type;
};
// Example of a trivial Templated class to hold some 3 items.
// Intent to have similar classes to hold 4,5..n items
template <typename T1, typename T2, typename T3>
class Store3Items : public StoreItemsBase
{
typedef typename arg_type<T1>::type arg1;
typedef typename arg_type<T2>::type arg2;
typedef typename arg_type<T3>::type arg3;
public:
Store3Items(arg1 t1, arg2 t2, arg3 t3)
:
StoreItemsBase(),
mT1(t1),
mT2(t2),
mT3(t3)
{}
private:
T1 mT1;
T2 mT2;
T3 mT3;
};
// Function to create a pointer to our object with added id
// There would be similar CreateHolderFunctions for 4,5..n items
template <typename T1, typename T2, typename T3>
StoreItemsBase* CreateHolder(const T1 t1, const T2 t2, const T3 t3)
{
return new Store3Items<T1, T2, T3>(t1, t2, t3);
}
int main()
{
int testInt=3;
double testDouble=23.4;
const std::string testStr("Hello World");
StoreItemsBase* Ok1 = CreateHolder(testInt, testDouble, testStr);
StoreItemsBase* Ok2 = CreateHolder(testDouble, testStr, testInt);
StoreItemsBase* Ok3 = CreateHolder(testStr, static_cast<const char*>("Hello there"), testInt);
// If you try a standard string, it compiler complains
// Although I could surround all my strings with the static cast, what I am looking for is a way
// to for the CreateHolder function to do the work for me
StoreItemsBase* NotOk4 = CreateHolder(testStr, "Hello World", testInt);
// Free our objects not shown in the example
}
Keep in mind, your class will be storing a raw const char* internally (not storing a std::string) so make sure the scope of that string being passed in will be longer lived than the pointer you're storing. Constant strings like in your example are fine because they live forever.

Related

Function template specialization in C++, no Instance of overloaded function

I'm learning about function template specialization in C++ and am tasked with writing a template function called plus that returns the sum of it's two arguments which maybe of different types. One version that accepts by value and another by pointer. As an added challenge, I'm asked to overload this function so that it concatenates two strings.
template <typename T1, typename T2> decltype(auto) plus(const T1& a, const T2& b) {
return a + b;
}
template <typename T1, typename T2> decltype(auto) plus(const T1* a, const T2* b) {
return *a + *b;
}
// concatenate two strings
template <>
std::string_view plus<std::string_view, std::string_view> (std::string_view a, std::string_view b) {
return std::string { a } + std::string{ b };
}
The problem is that I'm getting an error on the specialization overload of the function to concatenate two strings. The reason I decided to choose std::string_view over std::string is so that when calling the function with string literals (const char*) it wouldn't resolve to the second definition that accepts a const * which I'm guessing would be resolved over std::string.
So I can't really figure out what's going on. Just a wild guess but maybe this has something to do with me having two different template functions called plus and it can't figure out which one I'm trying to specialize / overload?
UPDATE:
The issue seems to be with template resolution. The definition that accepts const T* is always preferred for any string literals. Just trying to find a fix.
This would be my suggestion:
template <typename T1, typename T2, typename T3> T3 plus(const T1& a, const T2& b) {
return a + b;
}
template <typename T1, typename T2, typename T3> T3 plus(const T1* a, const T2* b) {
return *a + *b;
}
template <typename T1, typename T2, typename T3> T3 plus(T1 a, T2 b) {
return a + b;
}
// concatenate two strings
template <>
std::string plus<std::string_view, std::string_view> (std::string_view a, std::string_view b) {
return std::string(a).append(b);
}
Since string views needs to refer to the content of another string you need to return a string since the newly created string_view would point to a temporary object.
Also there is no way to concatenate 2 string_view's together since concatenating two strings together would require that string_view's are able to hold references to other string views (since they don't hold string content themselves).
Furthermore, a third typename is required since this implementation would return another type (std::string) since you don't want to return a string_view of a temporary
If you have access to C++20, then this could be done pretty easily with concepts.
Anything that's convertible to string_view, such as string and const char*, will be taken to this function:
template<typename T>
concept StringView = std::convertible_to<T, std::string_view>;
auto plus(StringView auto a, StringView auto b)
{
return std::string(a).append(b);
}
Similarly, you can define other concepts easily and just exlucde StringView:
template<typename T>
concept Reference = std::is_reference_v<T> && !StringView<T>;
template<typename T>
concept Pointer = std::is_pointer_v<T> && !StringView<T>;
auto plus(const Reference auto a, const Reference auto b)
{
⋮
⋮

A compile-time counter for distinct Type identifier

I am writing some template meta programming code. For some reasons, I want to make every object in my code has different type. The original code looks like this:
template<unsigned int index>
class Class1{
};
template<typename T1, typename T2, unsigned int index>
class Class2{
std::tuple<T1*, T2*> v;
public:
Class2(T1* t1, T2* t2): v(std::tuple<T1*, T2*>(t1, t2)) {}
};
template<unsigned int index>
auto makeClass1() {
return Class1<index>();
}
template<unsigned int index, typename T1, typename T2>
auto mul(T1& t1, T2& t2) {
return Class2<T1, T2, index>(&t1, &t2);
}
int main() {
auto t1 = makeClass1<0>(); // Type of TT1 is Class1<0>
auto t2 = makeClass1<1>(); // Type of TT2 is Class1<1>
auto m1 = mul<0>(t1, t2);
auto m2 = mul<1>(t1, t2); // Type of m2 is different from type of m1.
}
This code is work, but I wish my code is easy to use. So I want to ask is there any solution that can make the code look like this:
template<unsigned int index>
class Class1{
};
template<typename T1, typename T2, unsigned int index>
class Class2{
std::tuple<T1*, T2*> v;
public:
Class2(T1* t1, T2* t2): v(std::tuple<T1*, T2*>(t1, t2)) {}
};
template<unsigned int index = IncreaseCounter<?>::value>
auto makeClass1() {
return Class1<index>();
}
template<unsigned int index = IncreaseCounter<?>::value, typename T1, typename T2>
auto operator*(T1& t1, T2& t2) {
return Class2<T1, T2, index>(&t1, &t2);
}
int main() {
auto t1 = makeClass1(); // Type of TT1 is Class1<0>
auto t2 = makeClass1(); // Type of TT2 is Class1<1>
auto m1 = t1*t2
auto m2 = t1*t2; // Type of m2 is different from type of m1.
}
Note: I think I need a compile-time counter. But except the macro solution:__COUNTER__ and __LINE__ , I can't find any other compile-time solution. The macro solution is ineffective to my code.
Except the compile-time counter, any other solution is ok.
Thank you for reading my question. Due to my poor english expression ability,please bear with me for the wrong sentences.
In C++20, you might do:
template <typename = decltype([]{})>
class Class1{};
template<typename T1, typename T2, typename = decltype([]{})>
class Class2{
std::tuple<T1*, T2*> v;
public:
Class2(T1* t1, T2* t2): v(std::tuple<T1*, T2*>(t1, t2)) {}
};
template <typename T = decltype([]{})>
auto makeClass1() { return Class1<T>();}
template<typename T1, typename T2, typename T = decltype([]{})>
auto operator*(T1& t1, T2& t2) {
return Class2<T1, T2, T>(&t1, &t2);
}
int main() {
auto t1 = makeClass1();
auto t2 = makeClass1(); // Type of t2 is different from type of t1.
auto m1 = t1*t2;
auto m2 = t1*t2; // Type of m2 is different from type of m1.
static_assert(!std::is_same_v<decltype(t1), decltype(t2)>);
static_assert(!std::is_same_v<decltype(m1), decltype(m2)>);
}
Demo.
Let's regard the core of your question:
auto m1 = t1*t2;
auto m2 = t1*t2; // Type of m2 is different from type of m1.
You have exactly the same expression (t1*t2) but you wish this expression to produce two different types!
Overall your idea of counting objects in compile time is loose. What would you expect in this case?
for (int i = 0; i < 10; ++i) {
auto m = t1*t2;
}
Returning back to your code: you somehow need to introduce this compile-time index, like you do in mul<index>: either in mul or in the result type (explicit type instead of auto + appropriate conversion).

General min and max - C++

Writing a general minimum function, Two questions came to my mind. The code works fine with any input type and different argument number:
namespace xyz
{
template <typename T1, typename T2>
auto min(const T1 &a, const T2 &b) -> decltype(a+b)
{
return a < b ? a : b;
}
template <typename T1, typename T2, typename ... Args>
auto min(const T1 &a, const T2 &b, Args ... args) -> decltype(a+b)
{
return min(min(a, b), args...);
}
}
int main()
{
cout << xyz::min(4, 5.8f, 3, 1.8, 3, 1.1, 9) << endl;
// ^ ^ ^
// | | |
// float double int
}
Is there a better replacement for decltype(a+b)? I thing there's a standard class which I can't remember, something like decltype(std::THE_RESULT<a,b>::type).
The returned type of that decltype(std::THE_RESULT<a,b>::type)is const & or not ?
std::common_type(c++11):
For non-specialized std::common_type, the rules for determining the
common type between every pair T1, T2 are exactly the rules for
determining the return type of the ternary conditional operator where
T1 and T2 are the types of its second and the third operands.
and
For arithmetic types, the common type may also be viewed as the type
of the (possibly mixed-mode) arithmetic expression such as T0() + T1()
+ ... + Tn().
Not sure about const&, but you could play with std::remove_cv and std::remove_reference (and std::is_reference to find out the answer).
In fact, here's a list of type support utilities. Knock yourself out.
After the answer and worth comments I did it as below:
template <typename T1, typename T2>
auto min(const T1 &a, const T2 &b)
-> typename std::common_type<const T1&, const T2&>::type
{
return a < b ? a : b;
}
template <typename T1, typename T2, typename ... Args>
auto min(const T1 &a, const T2 &b, const Args& ... args)
-> typename std::common_type<const T1&, const T2&, const Args& ...>::type
{
return min(min(a, b), args...);
}

Making a tuple hold either a const reference or a const value

I'm trying to make a std::tuple that ends up holding either const references, or a value that was either copied or moved as appropriate where taking a reference wouldn't be sensible (e.g. temporaries).
So far I've got:
#include <functional>
#include <iostream>
template <typename ...Args>
struct foo {
const std::tuple<Args...> values;
};
template <typename T1, typename T2>
foo<T1, T2> make2(T1&& v1, T2&& v2) {
return foo<T1,T2>{std::tuple<T1, T2>(std::forward<T1>(v1),std::forward<T2>(v2))};
}
int main() {
double d1=1000;
double& d2 = d1;
auto f = make2(d2, 0);
std::cout << std::get<0>(f.values) << ", " << std::get<1>(f.values) << "\n";
d1 = -666;
std::get<0>(f.values)=0; // Allowed - how can I inject some more constness into references?
//std::get<1>(f.values) = -1; // Prohibited because values is const
std::cout << std::get<0>(f.values) << ", " << std::get<1>(f.values) << "\n";
}
Which is close, but not quite const enough for what I was hoping - I end up with a const std::tuple<double&, int> which of course allows me to modify the double that the tuple refers to.
I tried sprinkling some more constness into make2:
template <typename T1, typename T2>
foo<T1 const, T2 const> make2(T1&& v1, T2&& v2) {
return foo<T1 const,T2 const>{std::tuple<T1 const, T2 const>(std::forward<T1>(v1),std::forward<T2>(v2))};
}
That succeeded in making the int (i.e. non-reference) tuple member const (not terribly exciting given I can make the whole tuple const easily enough), but did nothing to the double& member. Why? How can I add that extra constness?
It didn't work because T1 const adds top-level const. I.e., it would make double &const, which is not different from double&. You need a inner const: "reference to const T1".
You could build this up with a combination of remove_reference, add_const and add_reference, or just write a small trait that puts the const in the right place:
template <typename T>
struct constify { using type = T; };
// needs a better name
template <typename T>
struct constify<T&> { using type = T const&; };
// and an alias for UX ;)
template <typename T>
using Constify = typename constify<T>::type;

How to determine the type of a function parameter given the type of argument passed to it?

I need a type trait which will report the type of a functor's operator() parameter given the type of the functor and the type of an argument passed to it. Basically, I need to determine precisely what type the argument will be converted to when passing it to the functor. For simplicity, let's assume that I'm only interested in a (potentially templated, potentially overloaded) operator() with a single argument. Unfortunately, I'm limited to c++03. Can it be done? If not, how about c++11?
Here's one example:
#include <cassert>
#include <type_traits>
template<typename Functor, typename Argument>
struct parameter_type
{
// what goes here?
typedef ... type;
};
struct takes_float_cref
{
void operator()(const float &);
};
int main()
{
// when calling takes_float_cref::operator() with an int,
// i'd expect a conversion to const float &
assert(std::is_same(parameter_type<takes_float_cref, int>::type, const float &>::value);
return 0;
}
A related question (whose answer doesn't give me quite what I need) gives the context for needing such a trait. I've put further unit tests on ideone.
I am afraid that this is not exactly possible without help from your client.
TL;DR: unit test fail (grrr gcc).
The general case of your question is this functor:
struct Functor {
template <typename T>
typename std::enable_if<std::is_integral<T>::value>::type
operator()(T t) const;
void operator(double d) const;
};
It combines the two main issues here:
If there is an overload, then taking &F::operator() requires a static_cast to a given type to disambiguate which overload should be used
Templates (and arbitrary conditions to express them) cannot be succintly expressed as typedefs
Therefore, the client (Functor here) need to provide additional hooks for you if you truly wish to get this type. And without decltype I don't see how to get it (note, gcc provides typeof as an extension in C++03).
Getting the client to give us hints:
// 1. Make use of the return value:
struct Functor {
template <typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
operator()(T t) const;
double operator(double d) const;
};
// 2. Double up the work (but leave the return value as is)
struct Functor {
template <typename T>
static typename std::enable_if<std::is_integral<T>::value, T>::type Select(T);
static double Select(T);
template <typename T>
typename std::enable_if<std::is_integral<T>::value>::type
operator()(T t) const;
void operator(double d) const;
};
Let's say we go for the second case (leaving the return value free for another use).
template <typename F, typename T>
struct parameter {
static T t;
typedef decltype(F::Select(t)) type;
};
In C++03, replace decltype by typeof with gcc.
I don't see a way to forego decltype. sizeof does provides an unevaluated context but it does not seem to help much here.
Unit Tests Here.
Unfortunately, there is a gcc bug it seems with the references, and float& gets reduced to float (and any other reference really), the bug remains with decltype so it's just a buggy implementation :/ Clang 3.0 has no problem with the C++11 version (decltype) but does not implement typeof I think.
This can be worked around by requiring the client to use a ref<float> class instead, and then unwrapping it. Just a bit more burden...
To get started I would go with this:
template<typename F>
struct parameter_type_impl;
// may be with variadic arguments
template<typename R, typename A, typename F>
struct parameter_type_impl<R (F::*)(A)> {
typedef A type;
};
template<typename F>
struct parameter_type {
typedef typename parameter_type_impl<decltype(&F::operator())>::type type;
};
I don't see why you would pass in the actual argument type. If the
conversion is not able to take place you have to use special measures
(e.g. SFINAE) later on. I think the two things are orthogonal:
deducing the argument type, then deciding if the argument you would
like to pass in is convertible.
The non-C++03 decltype is hard to get rid of. Specifying a function
type always requires knowledge of the arguments. As soon as you would
spell out the arguments, the whole thing would be moot.
The same problem would occur with Boost.Function Types.
#include <iostream>
template< typename PParameter00 = void, typename PParameter01 = void, typename PParameter02 = void, typename PParameter03 = void >
struct TIdentityParameter // Users need to inherit from it. Add more types as needed.
{
typedef PParameter00 TType00;
typedef PParameter01 TType01;
typedef PParameter02 TType02;
typedef PParameter03 TType03;
};
struct TUserFunctor00 : public TIdentityParameter< float const &, int, void * >
{
void operator()( float const &, int, void * );
// or they can do
//void operator()( TType00, TType01, TType02 );
};
struct TUserFunctor01 : public TIdentityParameter< char const *, double >
{
void operator()( char const*, double );
// or they can do
//void operator()( TType00, TType01 );
};
template< bool pValue >
struct TValueBool
{
static bool const sValue = pValue;
};
template< typename PType00, typename PType01 >
struct TIsSame : public TValueBool< false >
{
};
template< typename PType >
struct TIsSame< PType, PType > : public TValueBool< true >
{
};
int main( void )
{
std::cout << TIsSame< TUserFunctor00::TType02, void * >::sValue << std::endl;
std::cout << TIsSame< TUserFunctor01::TType00, double >::sValue << std::endl;
return ( 0 );
}
Code on [ideone][1]. I don't think it's asking too much from users to inherit from your struct in a pattern explained to them. After all, they want to work with your library. Anyway, maybe it's not what you are looking for.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EDIT: Here is something, maybe, a bit closer to the functionality JAred is looking for, but, I understand, the style does not appeal to him. Although, within C++03, I don't see how you can do it differently. Note, you can make TIdentityParameter take, say 16 template arguments to cover 16 possible types. Once again, yes, user has to inherit and specify types. Ideone:
#include <iostream>
struct TOneCrazyStruct
{
};
template< typename PParameter00 = TOneCrazyStruct, typename PParameter01 = TOneCrazyStruct, typename PParameter02 = TOneCrazyStruct,
typename PParameter03 = TOneCrazyStruct, typename PParameter04 = TOneCrazyStruct >
struct TIdentityParameter //Users will need to inherit from this struct as shown below.
{
typedef PParameter00 TType00;
typedef PParameter01 TType01;
typedef PParameter02 TType02;
typedef PParameter03 TType03;
typedef PParameter04 TType04;
};
struct TUserFunctor00 : public TIdentityParameter< float const &, int, void *, double >
{
void operator()( float const &, int, void * );
void operator()( double );
};
template< bool pValue >
struct TValueBool
{
static bool const sValue = pValue;
};
template< typename PType00, typename PType01 >
struct TIsSame : public TValueBool< false >
{
};
template< typename PType >
struct TIsSame< PType, PType > : public TValueBool< true >
{
};
template< typename PFunctor, typename PParameter >
struct THasType : public TValueBool<
TIsSame< typename PFunctor::TType00, PParameter >::sValue || TIsSame< typename PFunctor::TType01, PParameter >::sValue
|| TIsSame< typename PFunctor::TType02, PParameter >::sValue || TIsSame< typename PFunctor::TType03, PParameter >::sValue >
{
};
int main( void )
{
std::cout << THasType< TUserFunctor00, void * >::sValue << std::endl;
std::cout << THasType< TUserFunctor00, long double >::sValue << std::endl;
return ( 0 );
}