Making a function in a struct template [duplicate] - c++

This question already has answers here:
How to define a template member function of a template class [duplicate]
(2 answers)
Why can templates only be implemented in the header file?
(17 answers)
Closed 7 months ago.
So i made a template struct cause i want to be able to decide what type i give to my val. But when creating a function i don't know how to do it.
Here's what i'm doing:
In my .hpp
template<typename T>
struct Integer
{
T val;
void setUint(const T &input);
};
Now i can set what variable i want in the val and what i want in the function.
But now in my cpp i don't know how to invoke the function.
void Integer<T>::setUint(const T &input)
{
val = input;
}
Error: identifier "T" is undefined.

A template function is a way to operate with generic types (you may consider the type as an argument). Your template parameter T allows to pass different types to a function when you invoke the function (which means, simply said, you may replace T with some other types int, double, ...)
Please, have a look at the following simple example.
#include <iostream>
#include <typeinfo>
// you may put it all in a hpp and thus include the hpp file in the CPP
template<typename T>
struct Integer
{
T val;
void setUint(const T &input){
val=input;
std::cout <<"the type is " << typeid(T).name() << " value is "<< val << std::endl;
}
};
// or look at Jarod42's implementation details.
/*
template<typename T>
void Integer<T>::setUint(const T &input){
val=input;
std::cout <<"the type is " << typeid(T).name() << " value is "<< val << std::endl;
}*/
// and here you have your cpp calling you template function with different types
int main()
{
Integer<double> value;
value.setUint(1500000);
Integer<int> value2;
value2.setUint(5);
return 0;
}

Syntax is
template <typename T>
void Integer<T>::setUint(const T &input)
{
val = input;
}

Also for templates, check if T actually matches your expectations. Your template will not make sense for types that are not Integers. Example on how to add these constraints here : https://godbolt.org/z/YsneKe7vj (both C++17 SFINAE, and C++20 concept)
#include <type_traits>
#include <string>
//-----------------------------------------------------------------------------------------------------------
// for C++17 setup a constexpr that will evaluate (at compile time, that's the constexpr bit)
// if a given type is an integer type
template<typename type_t>
constexpr bool is_integer_type_v = std::is_integral_v<type_t> && !std::is_same_v<type_t,bool>;
// create a template that can optionally be enabled. This is an example of a technique called SFINAE
template<typename type_t, typename enable = void>
struct Integer;
// for C++ define a specialization that will succesfully be enabled of integer types only
template<typename type_t>
struct Integer<type_t,std::enable_if_t<is_integer_type_v<type_t>>>
{
void Set(const type_t v)
{
value = v;
}
type_t value;
};
//-----------------------------------------------------------------------------------------------------------
// for C++20 use concepts
template<typename type_t>
concept is_integer = std::is_integral_v<type_t> && !std::is_same_v<type_t, bool>;
// note is_integer now replaces typename, and it can only accept types
// that satisfy the concept
template<is_integer integer_t>
struct IntegerCpp20
{
void Set(const integer_t v)
{
value = v;
}
integer_t value;
};
//-----------------------------------------------------------------------------------------------------------
int main()
{
//Integer<std::string> value; // will not compile;
Integer<int> value;
value.Set(2);
//IntegerCpp20<std::string> value; // will not compile;
IntegerCpp20<int> value20;
value20.Set(20);
return 0;
}

Related

C++ different using declarations for different concepts

Let's say, I have my List<T> class. I have a lot of functions where I have to pass a single object of my T type. For instance
void add(const T& item)
{
...
}
and it makes sense if T is some class or a struct. However, if T is a byte or integer, it's pointless or even wrong to pas it via reference, since memory pointer costs 8 bytes (4 on 32 bit system), i.e. I pass 1 byte size data type via 8 byte size pointer.
And so I decided to define argument data type using using directive. Kind of:
using argType = const T&; requires sizeof(T) > 8
using argType = T; requires sizeof(T) <= 8
But, obviously, this code doesn't work. Can you, please, propose me other solutions for that?
It sounds like what you need is conditional_t:
#include <type_traits>
template<class T>
class List {
using argType = std::conditional_t<(sizeof(T) > 8), const T&, T>;
void add(argType item) { }
};
To add to the answer provided here: https://stackoverflow.com/a/69864339/2963099 where conditional_t was suggested
It is important to make sure that items with non-trivial copy constructors are passed by reference, since a value copy can be very expensive. As such I would limit pass by value to trivially copyable objects.
Also using sizeof(T*) will work more generically than a hardcoded 8
Note that args are reversed and the test is to use pass by value, and objects with sizeof == 8 can still be pass by reference if needed.
using argType = std::conditional_t<
(sizeof(T) <= sizeof(T *)) && std::is_trivially_copyable_v<T>,
T, const T&>;
An example of usage:
#include <type_traits>
#include <vector>
#include <iostream>
struct Test
{
Test() : x{0}
{
std::cout << "Default construct" << std::endl;
}
Test(const Test& rhs) : x{rhs.x}
{
std::cout << "copy: " << x << std::endl;
}
int * x;
};
template<class T>
struct List {
using argType = std::conditional_t<(sizeof(T) <= sizeof(T *)) && std::is_trivially_copyable_v<T>, T, const T&>;
static argType copy(argType item)
{
std::cout << "Running Copy" << std::endl;
return item;
}
};
auto foo(typename List<Test>::argType t)
{
return List<Test>::copy(t);
}
auto goo(typename List<unsigned long long>::argType t)
{
return List<unsigned long long>::copy(t);
}
int main()
{
Test t;
std::cout << "Calling Test Copy" << std::endl;
foo(t);
std::cout << "After Test Copy" << std::endl;
unsigned long long u;
std::cout << "Calling ULL Copy" << std::endl;
goo(u);
std::cout << "After ULL Copy" << std::endl;
}
see it here: https://godbolt.org/z/WTKT8G6rh
Note, you can see the parameter of foo() and goo() easily here
Note how Test would have been passed by value and incurred a possibly expensive copy, but checking for an expensive copy prevents this
With c++20 concepts you can add some constraints to your templates,
from en.cppreference.com/w/cpp/language/constraints
Class templates, function templates, and non-template functions (typically members of class templates) may be associated with a constraint, which specifies the requirements on template arguments, which can be used to select the most appropriate function overloads and template specializations.
Named sets of such requirements are called concepts. Each concept is a predicate, evaluated at compile time, and becomes a part of the interface of a template where it is used as a constraint:
#include <string>
#include <cstddef>
#include <concepts>
// Declaration of the concept "Hashable", which is satisfied by any type 'T'
// such that for values 'a' of type 'T', the expression std::hash<T>{}(a)
// compiles and its result is convertible to std::size_t
template<typename T>
concept Hashable = requires(T a) {
{ std::hash<T>{}(a) } -> std::convertible_to<std::size_t>;
};
struct meow {};
// Constrained C++20 function template:
template<Hashable T>
void f(T) {}
//
// Alternative ways to apply the same constraint:
// template<typename T>
// requires Hashable<T>
// void f(T) {}
//
// template<typename T>
// void f(T) requires Hashable<T> {}
int main() {
using std::operator""s;
f("abc"s); // OK, std::string satisfies Hashable
//f(meow{}); // Error: meow does not satisfy Hashable
}
In your case I think you can constraint your template as follows:
template<typename T>
concept InfTo8Bytes = requires(T a) {
sizeof (T) <= 8;
};
and use you concepts as follows:
template<InfTo8Bytes T>
class Foo {
};

Passing by value all types but string to a template function

I want to define a template function that gets one argument passed by value for all types but std::string (and const char*).
template<typename T>
void foo( T value )
{
// some code using value
}
The std::string version should behave exactly as the template version, but have its parameter passed by const&.
What is the best approach to do what I want without duplicating the body of foo()?
The best I was able to think is to wrap the code using value inside another function, and then call it inside all versions of foo() (the template version and the std::string overload). Is there another way? For example, is it possible to call the template version from within the std::string overload?
EDIT
What I want to know is a good rule of thumb for avoiding code duplication among various specializations and overloads. What is a good pattern to follow? Shall I define a wrapper function for the body and then call that from within all overloads/specializations, or there is another way?
In order to avoid code duplication, the answer by 101010 can be extended to actually call the template from within the overload:
#include <string>
#include <iostream>
#include <type_traits>
#include <boost/core/demangle.hpp>
template<typename T>
void foo( T value )
{
std::cout << "inside template" << std::endl;
std::cout << boost::core::demangle(typeid(value).name()) << std::endl;
}
void foo(const std::string &value)
{
std::cout << "inside const string overload" << std::endl;
foo<const std::string&>(value);
}
int main()
{
foo(10);
foo(std::string("hello"));
return 0;
}
output
inside template
int
inside const string overload
inside template
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >
live example
Simple solution: provide an overload for std::string:
void foo( std::string const &value ) {
// some code using value
}
I think what you are looking for is rvalue signature in C++ 11.
Its as simple as:
#include <iostream>
#include <string>
template<typename T>
void foo(T&& value)
{
std::cout << "was passed by refernece:" << std::is_lvalue_reference<T&&>::value << std::endl;
std::cout << value << std::endl;
}
int main()
{
std::string text = "hello";
foo(text);
foo(1);
}
You can either pass the parameter by reference or by value and the rvalue rules will use the appropriate type.
You can define a type-trait-like class that will convert std::string to std::string& and will keep the type for all other types:
template<class T>
struct helper {
typedef T type;
};
template<>
struct helper<std::string> {
typedef std::string& type; // or const std::string& type if you want
};
template<typename T>
void foo( typename helper<T>::type value, T value2 )
{
value = value2;
}
int main()
{
int a = 10;
foo(a, 42);
std::cout << a << std::endl; // prints 10
std::string s = "abc";
foo(s, std::string("def"));
std::cout << s << std::endl; // prints def
}
Full example: http://coliru.stacked-crooked.com/a/96cf78e6c4846172
UPD: as noted by #PiotrSkotnicki, having only one parameter makes type-deduction fail. However, I will keep the answer as it might be helpful in case you indeed have several parameters of type T or if you are ok with specifying explicit template parameter to foo.
UPD2: To solve the type-deduction problem, you may add another wrapper:
template<typename T>
void foo_helper( typename helper<T>::type value )
{
value = T();
}
template<typename T>
void foo(T& value)
{
foo_helper<T>(value);
}
This still might have some problems, so whether this is applicable to your usecase, is up to you to decide.
use std::enable_if + std::is_convertibale:
template<typename T>
typename std::enable_if<!std::is_convertible<T,std::string>::value>::type foo( T value )
{
// some code using value
}

get type of member memberpointer points to

I would like to extract the type of the member a member pointer points to.
template<someType myClass::*member>
void demo(myClass& instance, void* ptr) {
instance.*member = *reinterpret_cast<someType*>(ptr); // can the someType in this line be deduced from member?
}
I tried using decltype as suggested in the comments, however I have issues with this:
instance.*member= static_cast<decltype(instance.*member)>((*buffer)[offset]);
buffer is a std::shared_ptr<std::vector<uint8_t>>,
someType is uint32_t
I get the following error message:
error: invalid static_cast from type
‘__gnu_cxx::__alloc_traits >::value_type
{aka unsigned char}’ to type ‘uint32_t& {aka unsigned int&}’
As far as I understand decltype(instance.*member) with member defined as uint32_t instance::*member yields a reference uint32_t& rather than uint32_t. I tried to pass instance by value and the error remains. I am aware of std::remove_reference however, I do not understand how the reference gets to be there in the first place.
A further improvement would be if I could extract the someType without a class instance. However I have no clue how to achieve this, while I can get the class without a pointer by having the std lib like:
template <T*>
struct removePointer {
typedef T type;
}
I have no Idea how to write this in a form where I can get the someType part of the class, without knowing the class first. I could write something like the following however I would still have to pass the class naem and typename explicitly, is there a way to extract these automatically? Furthermore the following doe not compile in the first place (http://ideone.com/8VlKO4):
#include
using namespace std;
template <class C,typename T, T C::*v>
struct getPointerType {
typedef T type;
};
class Test {
int value;
};
int main() {
int Test::*member=nullptr;
cout << typeid(getPointerType<Test, int, decltype(member)>::type) << std::endl;
return 0;
}
Frankly, it's a bit hard to understand what you're trying to achieve, so I will focus on the updated part.
Clearly, you can not pass types (derived from decltype) as value arguments to the template. Moreover, you can not pass non constexpr values as template arguments (so you can not just stick the member variable into the template argument and expect it to compile).
However, you can rely on compiler to be able to deduce a correct function to call on non costexpr variable:
template <class C, typename T>
T getPointerType(T C::*v);
class Test {
int value;
};
int main() {
int Test::*member=nullptr;
cout << typeid(decltype(member)).name() << std::endl;
cout << typeid(decltype(getPointerType(member))).name() << std::endl;
return 0;
}
The above will print:
M4Testi //int Test::*
i //int
It is, of course, possible to "abuse" the template substitution even more:
template <typename M>
struct getPointerType {
template <typename C, typename T>
static T get_type(T C::*v);
typedef decltype(get_type(static_cast<M>(nullptr))) type;
};
class Test {
int value;
};
int main() {
int Test::*member=nullptr;
cout << typeid(getPointerType<decltype(member)>::type).name() << std::endl;
return 0;
}
The output will be the expected "i".
Here's a solution using template specialization technique :
#include <type_traits>
template <class T>
struct member_type_helper;
template <class C, class T>
struct member_type_helper<T C::*> { using type = T; };
template <class T>
struct member_type
: member_type_helper<typename std::remove_cvref<T>::type> {};
// Helper type
template <class T>
using member_type_t = member_type<T>::type;
Example of usage :
#include <iostream>
struct Foo { int i; };
int main()
{
auto ptr1 = &Foo::i;
auto const& ptr2 = &Foo::i;
volatile auto const ptr3 = &Foo::i; // let's go crazy
// prints true true true
std::cout << std::boolalpha
<< std::same_as<int, member_type_t<decltype(ptr1)>> << '\n'
<< std::same_as<int, member_type_t<decltype(ptr2)>> << '\n'
<< std::same_as<int, member_type_t<decltype(ptr3)>> << '\n';
}
I guess std::remove_cvref might be an overkill for most usage, but hey, it's free. If your compiler isn't >C++20 compliant, you could use std::remove_cv instead (> C++11).

how to do an if else depending type of type in c++ template? [duplicate]

This question already has answers here:
using std::is_same, why my function still can't work for 2 types
(4 answers)
Closed 2 years ago.
// template specialization
#include <iostream>
using namespace std;
// class template:
template <class T>
class mycontainer {
T element;
public:
mycontainer (T arg) {element=arg;}
T increase () {
//if(T.type==int)//how to do this or something similar?
//do this if an int
return ++element;
//if(T.type==char)
//if ((element>='a')&&(element<='z'))
//element+='A'-'a';
//return element;
}
};
I know how to write a template specialization and do a separate whole class def just for the char type.
But what if I wanted to handle everything in just one block of code?
How can I check if T is an int or a char?
You could use typeid:
if (typeid(T) == typeid(int))
Or you could use the std::is_same type trait:
if (std::is_same<T, int>::value)
What you want is probably something like a compile-time if.
Unfortunately, C++11 has no native support for such a language construct.
However, if you just want to check whether two types are identical, the std::is_same<> type trait should help you:
#include <type_traits> // <== INCLUDE THIS STANDARD HEADER
// class template:
template <class T>
class mycontainer
{
T element;
public:
mycontainer (T arg) {element=arg;}
T increase ()
{
if (std::is_same<T, int>::value) // <== THIS IS HOW YOU WOULD USE IT
return ++element;
if (std::is_same<T, char>::value) // <== THIS IS HOW YOU WOULD USE IT
{
if ((element>='a') && (element<='z'))
element+='A'-'a';
}
return element;
}
};
However, keep in mind that the condition is evaluated at run-time, even though the value of is_same<T, int>::value is known at compile-time. This means that both the true and the false branch of the if statement must compile!
For instance, the following would not be legal:
if (std::is_same<T, int>::value)
{
cout << element;
}
else if (std::is_same<T, my_class>::value)
{
element->print(); // Would not compile when T is int!
}
Also, as Xeo correctly pointed out in the comments, the compiler will likely issue warnings because your condition will always evaluate to true or to false, so one of the two branches will contain unreachable code.
You may use explicit template specialization
#include <iostream>
using namespace std;
// class template:
template <class T>
class mycontainer {
T element;
public:
mycontainer (T arg) {element=arg;}
T increase();
};
template<>
int mycontainer<int>::increase(){
return ++element;
}
template<>
char mycontainer<char>::increase(){
if ((element>='a')&&(element<='z'))
element+='A'-'a';
return element;
}
int main(){
mycontainer<int> A(10);
mycontainer<char> B('x');
cout << A.increase() <<endl;
cout << B.increase() <<endl;
return 0;
}
How about a simple overload?
// in the private section
static int& do_increase(int& i){ return ++i; }
static char& do_increase(char& c){
if(c >= 'a' && c <= 'z')
c += 'A' - 'a';
return c;
}
template<class U>
static U& do_increase(U& arg){
// some default implementation?
return arg;
}
(Note that the standard doesn't guarantee alphabetic order for the numeric values of a char.)
Then simply call that in increase as return do_increase(element);.
The usual solution here is to forward to an overloaded function
with an additional argument. Something like:
template <typename T>
class MyContainer
{
T increase( int const* ) { /* special treatment for int */ }
T increase( ... ) { /* default treatment */ }
public:
T increase()
{
return increase( (T const*)0 );
}
};
With a little imagination, you can come up with all sorts of
distinctions. If you make the target functions with the extra
arguments templates, you can even leverage off SFINAE: design
the dummy argument so that template type substitution fails, and
the function will not be considered in the overload set. And
since all of the functions are inline, it's probable that there
will be no extra overhead, provided that you optimize.
This is along the lines of Andy Prowls answer but is all done at compile-time using a minimal helper class with specialization.
In this instance you have a helper that actually does the specialization but you could also have the helper class just take a bool and then use something like std::is_same<T, int>::value to pass that value as a template parameter.
template <typename T>
struct myContainerHelper;
{
// General Case
static inline T increase(T element)
{
return ++element;
}
};
template <>
struct myContainerHelper<char>
{
// Specific case
static inline char increase(char element)
{
if ((element>='a')&&(element<='z')) element+='A'-'a';
return element;
}
};
template <class T>
class mycontainer
{
T element;
public:
mycontainer (T arg) {element=arg;}
T increase ()
{
return myContainerHelper<T>::increase(element);
}
};
This allows you to only specialize the single function instead of the entire class. I'm using a template class with statics because I'm used to VS2012 limitations with partial specialization for function templates.

Checking if a function with a given signature exists in c++

So I was looking for ways to check whether a function with a particular argument exists. I have a templated method which relies on an external function (external from the class) to do the job:
template <class Moo>
void exportDataTo(Moo& ret){
extended_solid_loader(ret, *this);
}
At multiple points in the project I have macros which define extended_solid_loader for different types, but now I want to be able to use a default function if extended_solid_loader hasn't been defined for that particular class type.
I came across this:
Is it possible to write a template to check for a function's existence?
but it seems a little different, in that I'm not checking for a method, but rather a definition of a function with a particular argument type.
Is this possible right now?
You can just provide a function template for extended_solid_loader providing a default implementation, and users who want to use something other than the default implementation just specialize that.
template<class T>
void extended_solid_loader(T & ret, SomeClass & obj) {
// default implementation here
}
template<>
void extended_solid_loader<MooClass>(MooClass & ret, SomeClass & obj) {
// special implementation for MooClass here
}
You don't actually have to do anything particularly special. Just make sure there's a version of that function available to the template and let ADL do the dirty work. Check out this example:
#include <iostream>
namespace bob {
struct X {};
void f(X const&) { std::cout << "bob::f\n"; }
}
namespace ed {
template < typename T >
void f(T const&) { std::cout << "ed::f\n"; }
template < typename T >
struct test
{
void doit() // not called f and no other member so named.
{ f(T()); }
};
}
int main()
{
ed::test<int> test1;
ed::test<bob::X> test2;
test1.doit();
test2.doit();
std::cin.get();
}
Works without the namespace stuff too (non-templates have preference). I just used that to show that ADL will pick it up when you do.
Your original question was interesting. Found a way to do it in C++0x:
template < typename T >
struct fun_exists
{
typedef char (&yes) [1];
typedef char (&no) [2];
template < typename U >
static yes check(decltype(f(U()))*);
template < typename U >
static no check(...);
enum { value = sizeof(check<T>(0)) == sizeof(yes) };
};
void f(double const&) {}
struct test {};
#include <iostream>
int main()
{
std::cout << fun_exists<double>::value << std::endl;
std::cout << fun_exists<test>::value << std::endl;
std::cin.get();
}