Reputation: 31
I wish to send an integer to a function, that integer might be 8/16 bits depending on conditions. Can I declare one function to receive either int8/in16 as argument, depending on what the caller sends? Or, do I have to declare two functions one for each type (what I am doing at present)?
void func(uint8_t/uint16_t value)
or
void func(uint8_t value) void func(uint16_t value)
Upvotes: 0
Views: 136
Reputation: 67733
void func(uint8_t/uint16_t value)
The only way to do this exactly (without a function template instantiated as two functions) is with std::variant
(or some other discriminated union).
void func(std::variant<uint8_t, uint16_t> value)
{
}
is precisely what you requested.
When you start implementing the body, you'll find it's often simpler to delegate to a templated visitor, and then you're back to the existing answers (but with a relatively expensive runtime decision about the type instead of a static one).
Demonstration in compiler explorer
void func(std::variant<uint8_t, uint16_t> value)
{
std::cout << "called with type index " << value.index() << '\n';
// templated visitor
std::visit(
[](auto && val)
{
std::cout << "called with type " << typeid(val).name()
<< ", value " << val << '\n';
},
value
);
// alternatively, test each type by hand
if (std::holds_alternative<uint8_t>(value))
{
std::cout << "got uint8_t alternative " << std::get<uint8_t>(value)
<< '\n';
}
else if (std::holds_alternative<uint16_t>(value))
{
std::cout << "got uint16_t alternative " << std::get<uint16_t>(value)
<< '\n';
}
}
Upvotes: 0
Reputation: 1022
@Jason Liam is onto it, but if you want to different functions, standard overloading is the answer. If you want to use a single function for those two types, combine Jason's functions:
#include <cstdint>
#include <iostream>
#include <typeinfo>
template <typename T> void func(const T& t) requires
std::is_same_v<T, uint8_t> || std::is_same_v<T, uint16_t>
{
std::cout << "called with type " << typeid(T).name() <<std::endl;
}
int main()
{
uint8_t x = 4;
func(x); //calls uint8_t version
uint16_t y = 4;
func(y); //calls uint16_t version
int z = 6;
// func(z); compiler error, z is not right type
}
Upvotes: 2
Reputation: 1
With C++20, we can use requires
clause instead of SFINAE to do the same:
#include <cstdint>
#include <iostream>
template <typename T> void func(const T& t) requires std::is_same_v<T, uint8_t>
{
std::cout << "uint8 version called" <<std::endl;
}
template <typename T> void func(const T& t) requires std::is_same_v<T, uint16_t>
{
std::cout << "uint16 version called" <<std::endl;
}
int main()
{
uint8_t x = 4;
func(x); //calls uint8 version
uint16_t y = 4;
func(y); //calls uint16_t version
}
Upvotes: 1
Reputation: 1
This can be done by using function template and SFINAE as shown below:
#include <cstdint>
#include <iostream>
template <typename T> std::enable_if_t<std::is_same_v<T, uint8_t>> func(const T& t)
{
std::cout << "uint8 version called" <<std::endl;
}
template <typename T> std::enable_if_t<std::is_same_v<T, uint16_t>> func(const T& t)
{
std::cout << "uint16 version called" <<std::endl;
}
int main()
{
uint8_t x = 4;
func(x); //calls uint8 version
uint16_t y = 4;
func(y); //calls uint16_t version
}
Upvotes: 3