How to implement overloaded functions using templates in C++? - c++

Suppose I want to define a set of functions, each having 4 overloads, the first overload taking a single parameter of type int32_t and the second taking int64_t, the third - uint32_t and the fourth - uint64_t. For each function, all overloads have the same implementation so I could define a function template instead:
template <typename T>
void f(T t) {
// ...
}
However this is different from having four overloads because now I have a separate function for each (integer) type that can be used to instantiate f. The implementation details of f are such that it might not work for other integral types however. To address this I can wrap the function template in four overloaded functions:
template <typename T>
void f_impl(T t) {
// ...
}
void f(int32_t value) { f_impl(value); }
void f(int64_t value) { f_impl(value); }
void f(uint32_t value) { f_impl(value); }
void f(uint64_t value) { f_impl(value); }
It works but requires substantial amount of code for each function (4 function overloads + 1 function template). Is there a way to simplify this?
To clarify, it is not desirable to use template directly because it doesn't make sense (for implementation reasons or otherwise) to have its specializations for types other than int32_t, int64_t, uint32_t and uint64_t.
I've tried using std::enable_if already and the problem with it is best illustrated by this example:
#include <type_traits>
#include <iostream>
template <typename T>
struct is_supported_int {
static const bool value = false;
};
template <>
struct is_supported_int<int32_t> {
static const bool value = true;
};
template <>
struct is_supported_int<int64_t> {
static const bool value = true;
};
// ...
template <typename T, typename = typename std::enable_if<is_supported_int<T>::value, T>::type>
void f(T t) {
// ...
}
int main() {
short s = 42;
f(s);
}
Unlike in the original version with overloads which I'm trying to emulate, this example will not compile since f will be excluded from the set of matching functions for short.
Unfortunately std::is_integral<T> as suggested by Rapptz doesn't help either because due to implementation details of f this function can only be defined for specific types, not for all integral types.

Something like this would work.
#include <type_traits>
#include <iostream>
template<typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
void f(T t) {
std::cout << "int types only!\n";
}
int main() {
f(1.234f);
f(12);
}
f(1.234f) would fail to compile but f(12) wouldn't.

Use enable_if or a static assert to restrict instantiation.
#include <type_traits>
#include <cstdint>
template<bool X, bool Y>
struct or_ : std::true_type
{};
template<>
struct or_<false, false> : std::false_type
{};
template<typename T>
struct valid_type_for_f :
or_< std::is_same<T, std::uint32_t>::value,
std::is_same<T, std::uint64_t>::value> // etc.
{};
// static assert
template<typename T>
T f(T t) {
static_assert(valid_type_for_f<T>::value, "Not a valid type");
return t;
}
// enable_if
template<typename T>
typename std::enable_if<valid_type_for_f<T>::value, T>::type
fenable(T t) {
return t;
}
int main()
{
float x = 4.2f;
f(x); // fails
fenable(x); // fails
std::uint32_t xx = 23;
f(xx);
fenable(xx);
return 0;
}

Related

variadic arguments which are all a specialization of a template type

We can validate at compile time that an input to a function is a specialization of a template. I.E the following code validates that the input for f is some specialization of struct Holder.
template<typename T>
struct Holder<T> {...};
template<typename T>
void f(Holder<T> h) {...};
I want to validate that a set of variadic arguments are a specialization of a template.
More precisely I want to differentiate between two consecutive sets of variadic arguments - a set which is a specialization of a template, and a set which isn't.
Following is an example of how it might have looked like if the syntax allowed it to -
template<...Args1, ...Args2>
void f(Holder<Args1>.... args_which_are_specializations_of_Holder, Args2... args_which_are_not) {
use_holders(args_which_are_specializations_of_Holder...);
use_rest(args_which_are_not...);
return;
}
Is this possible ?
Thanks,
You can store the args in a tuple and calculate the index of the last Holder argument, then extract the Holder and normal arguments by index and forward them to the corresponding function.
#include <tuple>
template<class T>
constexpr bool is_holder = false;
template<class T>
constexpr bool is_holder<Holder<T>> = true;
template<class... Args>
void f(Args... args) {
constexpr auto holder_index = (is_holder<Args> + ... + 0);
auto args_tuple = std::tuple(args...);
[&args_tuple]<auto... Is>(std::index_sequence<Is...>) {
use_holders(std::get<Is>(args_tuple)...);
}(std::make_index_sequence<holder_index>{});
[&args_tuple]<auto... Is>(std::index_sequence<Is...>) {
use_rest(std::get<Is + holder_index>(args_tuple)...);
}(std::make_index_sequence<sizeof...(Args) - holder_index>{});
}
Demo
It's harder to mix variadic arguments like that. You can use std::tuple:
#include <tuple>
#include <cstdio>
template<class T>
struct Holder {
T value;
};
template <class ...T1, class ...T2>
void f(const std::tuple<Holder<T1>...>& holders, const std::tuple<T2...>& non_holders) {
std::printf("Holder count: %zu\n"
"Non-holder count: %zu\n", sizeof...(T1), sizeof...(T1));
}
int main() {
Holder<int> a{};
Holder<double> b{};
int c{};
double d{};
f(std::tuple{a, b}, std::tuple{c, d});
}

Execute function inside function template only for those types that have the function defined

I have a function template which takes many different types as it's input. Out of those types only one of them has a getInt() function. Hence I want the code to run the function only for that type. Please suggest a solution. Thanks
#include <type_traits>
#include <typeinfo>
class X {
public:
int getInt(){
return 9;
}
};
class Y{
};
template<typename T>
void f(T& v){
// error: 'class Y' has no member named 'getInt'
// also tried std::is_same<T, X>::value
if(typeid(T).name() == typeid(X).name()){
int i = v.getInt();// I want this to be called for X only
}
}
int main(){
Y y;
f(y);
}
If you want to be able to call a function f for all types that have function member getInt, not just X, you can declare 2 overloads for function f:
for types that have getInt member function, including class X
for all the other types, including class Y.
C++11 / C++17 solution
Having that in mind, you could do something like this:
#include <iostream>
#include <type_traits>
template <typename, typename = void>
struct has_getInt : std::false_type {};
template <typename T>
struct has_getInt<T, std::void_t<decltype(((T*)nullptr)->getInt())>> : std::is_convertible<decltype(((T*)nullptr)->getInt()), int>
{};
class X {
public:
int getInt(){
return 9;
}
};
class Y {};
template <typename T,
typename std::enable_if<!has_getInt<T>::value, T>::type* = nullptr>
void f(T& v) {
// only for Y
std::cout << "Y" << std::endl;
}
template <typename T,
typename std::enable_if<has_getInt<T>::value, T>::type* = nullptr>
void f(T& v){
// only for X
int i = v.getInt();
std::cout << "X" << std::endl;
}
int main() {
X x;
f(x);
Y y;
f(y);
}
Check it out live.
Please note that std::void_t is introduced in C++17, but if you are limited to C++11, then it is really easy to implement void_t on your own:
template <typename...>
using void_t = void;
And here is C++11 version live.
What do we have in C++20?
C++20 brings lots of good things and one of them is concepts. Above thing that's valid for C++11/C++14/C++17 can be significantly reduced in C++20:
#include <iostream>
#include <concepts>
template<typename T>
concept HasGetInt = requires (T& v) { { v.getInt() } -> std::convertible_to<int>; };
class X {
public:
int getInt(){
return 9;
}
};
class Y {};
template <typename T>
void f(T& v) {
// only for Y
std::cout << "Y" << std::endl;
}
template <HasGetInt T>
void f(T& v){
// only for X
int i = v.getInt();
std::cout << "X" << std::endl;
}
int main() {
X x;
f(x);
Y y;
f(y);
}
Check it out live.
You might use if constexpr from C++17:
template<typename T>
void f(T& v){
if constexpr(std::is_same_v<T, X>) { // Or better create trait has_getInt
int i = v.getInt();// I want this to be called for X only
}
// ...
}
Before, you will have to use overloads and SFINAE or tag dispatching.
Keep it simple and overload. Has worked since at least C++98...
template<typename T>
void f(T& v)
{
// do whatever
}
void f(X& v)
{
int result = v.getInt();
}
This is enough if there only ever one type with getInt function. If there's more, it's not so simple anymore. There are several ways to do it, here's one:
struct PriorityA { };
struct PriorityB : PriorityA { };
template<typename T>
void f_impl(T& t, PriorityA)
{
// generic version
}
// use expression SFINAE (-> decltype part)
// to enable/disable this overload
template<typename T>
auto f_impl(T& t, PriorityB) -> decltype(t.getInt(), void())
{
t.getInt();
}
template<typename T>
void f(T& t)
{
f_impl(t, PriorityB{ } ); // this will select PriorityB overload if it exists in overload set
// otherwise PriorityB gets sliced to PriorityA and calls generic version
}
Live example with diagnostic output.

C++ How to specialize a template using vector<T>?

Basicly ,I want to make a function behave differently for a vector(type) parameter and a non-vector type parameter .
#include <vector>
using namespace std;
template <typename type>
struct is_vector {
static const bool value = false;
};
template <typename type>
struct is_vector<vector<type>>
{
static const bool value = true;
};
template <typename type>
type read()
{
if (is_vector<type>::value)
{
type vec(10);
vec.front()=1;//left of '.front' must have class/struct/union
return vec;
}
else
{
return{};
}
}
int main()
{
auto i= read<int>();
}
I want to return a vector while using vector as the typename ,return an int while using int as the typename .
But since is_vector(int)::value returns false ,why would my compiler reports "left of '.front' must have class/struct/union" ?How can I make it work ?
What I want to achieve is to correctly deserialize a string to a vector(type) or a vector(vector(type)) .
I need to recursively call the read function ,while passing a multidemonsional vector as a template parameter ,but the compiler forbids me to do it .
template <typename type>
struct is_vector {
static const bool value = false;
};
template <typename type>
struct is_vector<vector<type>>
{
static const bool value = true;
};
template <typename type>
type read(char*& str)
{
if (is_vector<type>::value)
{
type vec(read<uint8_t>(str));
for (auto& e : vec)
e = read<type::value_type>(str);
return vec;
}
return *reinterpret_cast<type*>((str += sizeof(type)) - sizeof(type));
}
So I tried specialization .
template<>
vector<int> read<vector<int>>(char*& str)
{
vector<int> vec(read<uint8_t>(str));
for (auto& e : vec)
e = read<int>(str);
return vec;
}//works
template <typename type>
template <>
vector<type> read<vector<type>>(char*& str)
{
vector<type> vec(read<uint8_t>(str));
for (auto& e : vec)
e = read<type>(str);
return vec;
}//don't work
Do I really need to manually rewrite my read function for every kind of types I use ?
(like vector(vector(vector(int)))?)
You want a function template foo<R> that is parameterized at least
by return type R, and you want a specialized implementation
when R = std::vector<U>, for arbitrary type U.
It doesn't matter what the arguments of foo<R> may be, so for illustration
we'll assume there aren't any. Here's how you do that:
Define a trait template as follows:
template<typename T>
struct is_vector
{
static constexpr bool value = false;
};
template<template<typename...> class C, typename U>
struct is_vector<C<U>>
{
static constexpr bool value =
std::is_same<C<U>,std::vector<U>>::value;
};
With this,
is_vector<T>::value
will be true at compiletime if and only if T = std::vector<U>, for some U.
Then define two overloads of foo<R>() on the following lines:
template <typename R>
std::enable_if_t<!is_vector<R>::value,R> foo()
{
// Your non-vector implementation instead of...
std::cout <<
"In non-vector specialization of `foo<R>()`\n";
return R();
}
template <typename R>
std::enable_if_t<is_vector<R>::value,R> foo()
{
// Your vector implementation instead of...
std::cout <<
"In vector specialization of `foo<R>()`\n";
return R();
}
These two overloads are mutually exclusive and jointly exhaustive. The
first overload pans out to be legal code if and only if is_vector<R>::value is false. The
second overload pans out to be legal code if and only if is_vector<R>::value is true.
That's thanks to the behaviour of std::enable_if,
which you should study and understand.
When the compiler needs to pick one these template overloads to implement some
call foo<type>() that it finds in your code, it discovers that exactly one of the overloads
won't even compile when type is plugged in for the template parameter R. The first one won't compile if
type is some std::vector<U> and the second one won't compile if type is not some
std::vector<U>. Helpfully, the compiler picks the one that it can compile.
That's called SFINAE ("Substitution Failure Is Not An Error"),
and it's the solution of your problem.
Here's an illustrative program:
#include <vector>
#include <type_traits>
#include <iostream>
template<typename T>
struct is_vector
{
static constexpr bool value = false;
};
template<template<typename...> class C, typename U>
struct is_vector<C<U>>
{
static constexpr bool value =
std::is_same<C<U>,std::vector<U>>::value;
};
template <typename R>
std::enable_if_t<!is_vector<R>::value,R> foo()
{
// Your non-vector implementation instead of...
std::cout <<
"In non-vector specialization of `foo<R>()`\n";
return R();
}
template <typename R>
std::enable_if_t<is_vector<R>::value,R> foo()
{
// Your vector implementation instead of...
std::cout <<
"In vector specialization of `foo<R>()`\n";
return R();
}
int main()
{
auto i = foo<int>();
(void)i;
auto vc = foo<std::vector<char>>();
(void)vc;
return 0;
}
which will output:
In non-vector specialization of `foo<R>()`
In vector specialization of `foo<R>()`
(gcc 6.1/clang 3.8, -std=c++14 see live)

How can a C++ template be specialized for all 32-bit POD types?

I've developed a simple template function for swapping the byte order of a single field:
template <typename T> inline void SwapEndian(T& ptr) {
char *bytes = reinterpret_cast<char*>(&ptr);
int a = sizeof(T) / 2;
while (a--) {
char tmp = bytes[a];
int b = sizeof(T) - 1 - a;
bytes[a] = bytes[b];
bytes[b] = tmp;
}
}
I'll often use it where T = int or float. Both of these types are represented by 4 bytes on the target platforms, and can be processed by the same specialization of the template.
Because this function sometimes is responsible for processing large buffers of raw data, I've created an optimized specialization:
template<> inline void SwapEndian(float& ptr) {
#if defined(__GNUC__)
*reinterpret_cast<unsigned*>(&ptr) = __builtin_bswap32(*reinterpret_cast<unsigned*>(&ptr));
#elif defined(_MSC_VER)
*reinterpret_cast<unsigned*>(&ptr) = __byteswap_ulong(*reinterpret_cast<unsigned*>(&ptr));
#endif
}
This specialization also works with 32-bit integers, signed or unsigned, so I have a big smelly pile of duplicates with only the type name different.
How do I route all instantiations of 4 byte POD types through this one template? (PS. I'm open to solving this in a different way, but in that case I'd like to know definitively whether or not it's possible to build these kind of meta-specialized templates.)
EDIT: Thanks everyone, after reading the answers and realizing that arithmetic is a better restriction than pod, I was inspired to write something. All the answers were useful but I could only accept one, so I accepted the one that appears to be structurally the same.
template<bool, bool> struct SwapEndian_ { template<typename T> static inline void _(T&); };
template<> template<typename T> inline void SwapEndian_<true, true>::_(T& ptr) {
// ... stuff here ...
}
// ... more stuff here ...
template<typename T> inline void SwapEndian(T& ptr) {
static_assert(is_arithmetic<T>::value, "Endian swap not supported for non-arithmetic types.");
SwapEndian_<sizeof(T) & (8 | 4), sizeof(T) & (8 | 2)>::template _<T>(ptr);
}
When in doubt, tag dispatch.
This implementation has 2 traits -- is_pod and get_sizeof_t. The base override dispatches to SwapEndians with those two traits tagged. There is also a is_pod override, and an override (which I'd advise =deleteing) for non-pod types.
Extension to new traits and types is relatively easy.
template<size_t n>
using sizeof_t = std::integral_constant<size_t, n>;
template<class T>
using get_sizeof_t = sizeof_t<sizeof(T)>;
template <class T>
void SwapEndian(T& t, std::true_type /*is pod*/, sizeof_t<4>) {
std::cout << "4 bytes!\n";
// code to handle 32 bit pods
}
template <class T, size_t n>
void SwapEndian(T& t, std::true_type /*is pod*/, sizeof_t<n>) {
std::cout << "pod\n";
// code to handle generic case
}
template <class T, size_t n>
void SwapEndian(T& t, std::false_type /*is pod*/, sizeof_t<n>) {
std::cout << "not pod\n";
// probably want to =delete this overload actually
}
template<class T>
void SwapEndian(T& t) {
SwapEndian(t, std::is_pod<T>{}, get_sizeof_t<T>{});
}
I am not sure if this is a good idea, but the above should do it.
Uses some C++14 features. Assumes CHAR_BIT is 8.
You should only rarely specialize template functions. Instead overload. Tag dispatching gives you the power of overload resolution to dispatch what code to run at compile time.
live example
I'm using a separate SwapEndian and SwapEndianImpl so that we can use template deduction and partial specialization.
template<bool> struct SwapEndianImpl
{
template<typename t> static inline void Func(t& n);
};
template<> template<typename t> void SwapEndianImpl<false>::Func(t& n)
{
std::cout << "not 32bit pod" << std::endl;
}
template<> template<typename t> void SwapEndianImpl<true>::Func(t& n)
{
std::cout << "32bit pod" << std::endl;
}
template<typename t> inline void SwapEndian(t& n)
{
SwapEndianImpl<std::is_pod<t>::value && sizeof(t) == (32 / CHAR_BIT)>::template Func<t>(n);
}
I believe that this is a better way to go than SFINAE if you specialize to more than two conditions.
You might limit your swap on arithmetic types (not using all POD types) and use specialized template classes for flexibility:
#include <climits>
#include <iostream>
#include <type_traits>
namespace Detail {
template <
typename T,
unsigned N = sizeof(T) * CHAR_BIT,
bool Swap = std::is_arithmetic<T>::value>
struct SwapEndian
{
static void apply(T&) {
std::cout << "Not Swapping\n";
}
};
template <typename T>
struct SwapEndian<T, 16, true>
{
static void apply(T&) {
std::cout << "Swapping\n";
}
};
template <typename T>
struct SwapEndian<T, 32, true>
{
static void apply(T&) {
std::cout << "Swapping\n";
}
};
template <typename T>
struct SwapEndian<T, 64, true>
{
static void apply(T&) {
std::cout << "Swapping\n";
}
};
}
template <typename T>
void SwapEndian(T& value) {
Detail::SwapEndian<T>::apply(value);
}
struct Structure
{
char s[4];
};
static_assert(std::is_pod<Structure>::value, "Should be POD");
int main() {
char c;
short s;
int i;
long long l;
float f;
double d;
void* p;
Structure structure;
SwapEndian(c);
SwapEndian(s);
SwapEndian(i);
SwapEndian(l);
SwapEndian(f);
SwapEndian(d);
SwapEndian(p);
SwapEndian(structure);
}

Detecting a function in C++ at compile time

Is there a way, presumably using templates, macros or a combination of the two, that I can generically apply a function to different classes of objects but have them respond in different ways if they do not have a specific function?
I specifically want to apply a function which will output the size of the object (i.e. the number of objects in a collection) if the object has that function but will output a simple replacement (such as "N/A") if the object doesn't. I.e.
NO_OF_ELEMENTS( mySTLMap ) -----> [ calls mySTLMap.size() to give ] ------> 10
NO_OF_ELEMENTS( myNoSizeObj ) --> [ applies compile time logic to give ] -> "N/A"
I expect that this might be something similar to a static assertion although I'd clearly want to compile a different code path rather than fail at build stage.
From what I understand, you want to have a generic test to see if a class has a certain member function. This can be accomplished in C++ using SFINAE. In C++11 it's pretty simple, since you can use decltype:
template <typename T>
struct has_size {
private:
template <typename U>
static decltype(std::declval<U>().size(), void(), std::true_type()) test(int);
template <typename>
static std::false_type test(...);
public:
typedef decltype(test<T>(0)) type;
enum { value = type::value };
};
If you use C++03 it is a bit harder due to the lack of decltype, so you have to abuse sizeof instead:
template <typename T>
struct has_size {
private:
struct yes { int x; };
struct no {yes x[4]; };
template <typename U>
static typename boost::enable_if_c<sizeof(static_cast<U*>(0)->size(), void(), int()) == sizeof(int), yes>::type test(int);
template <typename>
static no test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(yes) };
};
Of course this uses Boost.Enable_If, which might be an unwanted (and unnecessary) dependency. However writing enable_if yourself is dead simple:
template<bool Cond, typename T> enable_if;
template<typename T> enable_if<true, T> { typedef T type; };
In both cases the method signature test<U>(int) is only visible, if U has a size method, since otherwise evaluating either the decltype or the sizeof (depending on which version you use) will fail, which will then remove the method from consideration (due to SFINAE. The lengthy expressions std::declval<U>().size(), void(), std::true_type() is an abuse of C++ comma operator, which will return the last expression from the comma-separated list, so this makes sure the type is known as std::true_type for the C++11 variant (and the sizeof evaluates int for the C++03 variant). The void() in the middle is only there to make sure there are no strange overloads of the comma operator interfering with the evaluation.
Of course this will return true if T has a size method which is callable without arguments, but gives no guarantees about the return value. I assume wou probably want to detect only those methods which don't return void. This can be easily accomplished with a slight modification of the test(int) method:
// C++11
template <typename U>
static typename std::enable_if<!is_void<decltype(std::declval<U>().size())>::value, std::true_type>::type test(int);
//C++03
template <typename U>
static typename std::enable_if<boost::enable_if_c<sizeof(static_cast<U*>(0)->size()) != sizeof(void()), yes>::type test(int);
There was a discussion about the abilities of constexpr some times ago. It's time to use it I think :)
It is easy to design a trait with constexpr and decltype:
template <typename T>
constexpr decltype(std::declval<T>().size(), true) has_size(int) { return true; }
template <typename T>
constexpr bool has_size(...) { return false; }
So easy in fact that the trait loses most of its value:
#include <iostream>
#include <vector>
template <typename T>
auto print_size(T const& t) -> decltype(t.size(), void()) {
std::cout << t.size() << "\n";
}
void print_size(...) { std::cout << "N/A\n"; }
int main() {
print_size(std::vector<int>{1, 2, 3});
print_size(1);
}
In action:
3
N/A
This can be done using a technique called SFINAE. In your specific case you could implement that using Boost.Concept Check. You'd have to write your own concept for checking for a size-method. Alternatively you could use an existing concept such as Container, which, among others, requires a size-method.
You can do something like
template< typename T>
int getSize(const T& t)
{
return -1;
}
template< typename T>
int getSize( const std::vector<T>& t)
{
return t.size();
}
template< typename T , typename U>
int getSize( const std::map<T,U>& t)
{
return t.size();
}
//Implement this interface for
//other objects
class ISupportsGetSize
{
public:
virtual int size() const= 0;
};
int getSize( const ISupportsGetSize & t )
{
return t.size();
}
int main()
{
int s = getSize( 4 );
std::vector<int> v;
s = getSize( v );
return 0;
}
basically the most generic implementation is always return -1 or "NA" but for vector and maps it will return the size. As the most general one always matches there is never a build time failure
Here you go. Replace std::cout with the output of your liking.
template <typename T>
class has_size
{
template <typename C> static char test( typeof(&C::size) ) ;
template <typename C> static long test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(char) };
};
template<bool T>
struct outputter
{
template< typename C >
static void output( const C& object )
{
std::cout << object.size();
}
};
template<>
struct outputter<false>
{
template< typename C >
static void output( const C& )
{
std::cout << "N/A";
}
};
template<typename T>
void NO_OF_ELEMENTS( const T &object )
{
outputter< has_size<T>::value >::output( object );
}
You could try something like:
#include <iostream>
#include <vector>
template<typename T>
struct has_size
{
typedef char one;
typedef struct { char a[2]; } two;
template<typename Sig>
struct select
{
};
template<typename U>
static one check (U*, select<char (&)[((&U::size)!=0)]>* const = 0);
static two check (...);
static bool const value = sizeof (one) == sizeof (check (static_cast<T*> (0)));
};
struct A{ };
int main ( )
{
std::cout << has_size<int>::value << "\n";
std::cout << has_size<A>::value << "\n";
std::cout << has_size<std::vector<int>>::value << "\n";
}
but you have to be careful, this does neither work when size is overloaded, nor when it is a template. When you can use C++11, you can replace the above sizeof trick by decltype magic