I'm writing a C++ library that contains a lot of function templates I want to explicitly instantiate and export for several type parameters. In my particular case, I have a lot of numeric function templates that I want to separately instantiate and compile for float, double, and long double. They look something like this:
template <typename T>
T calculate_a(T x) { ... }
template <typename T>
T calculate_b(T x, T y) { ... }
// ...
If I have M function templates and N underlying types, then I have M*N explicit instantiations to type out. Is it possible to write these instantiations more concisely?
My current solution is to use a preprocessor macro that performs all instantiations for a given type:
#define EXPLICITLY_INSTANTIATE(T) \
template T calculate_a<T>(T x); \
template T calculate_b<T>(T x, T y); \
// ...
EXPLICITLY_INSTANTIATE(float);
EXPLICITLY_INSTANTIATE(double);
EXPLICITLY_INSTANTIATE(long double);
However, this is suboptimal because it requires me to separately maintain another copy of each function template's signature. Also, if I want to do this in multiple translation units, then I need to separately maintain a list of underlying types in each. (Suppose that C++2a adds a long long double type that I want to support; I'll have to add EXPLICITLY_INSTANTIATE(long long double); to every file.)
Another possible approach is to gather up all of my functions into a (static-only) template class:
template <typename T>
class calculate {
T a(T x) { ... }
T b(T x, T y) { ... }
};
template class calculate<float>;
template class calculate<double>;
template class calculate<long double>;
This solves the first problem of separately maintaining two copies of each signature, but requires me to change each call of calculate_a into calculate::a<T>. It doesn't address the second problem.
You can avoid repeating function signatures by instantiating templates via taking their addresses:
// forward declarations in a header file
template<typename T>
T square(T num);
template<typename T>
T add(T left, T right);
// implementations and instantiations in a single implementation file
template<typename T>
T square(T num) {
return num * num;
}
template<typename T>
T add(T left, T right) {
return left + right;
}
// instantiations for specific types
#include <tuple>
template<typename... Ts>
auto instantiate() {
static auto funcs = std::tuple_cat(std::make_tuple(
add<Ts>,
square<Ts>
)...);
return &funcs;
}
template auto instantiate<int, double>();
The overhead here is a single array of pointers to all instantiated functions, example on godbolt.
This is what X Macros are made for. It works quite simply.
You have a file that contains all of the types you want to apply this to. Let's call it "type_list.inc". It would look like this:
X(float)
X(double)
X(long double)
When you want to perform some operation over that list of types, you #include the file, but around the point of inclusion, you #define the macro X to do the operation you want to perform:
#define X(T) \
template T calculate_a<T>(T x); \
template T calculate_b<T>(T x, T y); \
// ...
#include "type_list.inc"
#undef X
You still have to maintain two sets of function prototypes. But you only need to maintain one list of types.
I haven't clearly communicated my intent in the question. The purpose of my explicit instantiations isn't to limit the types that these functions can be called with, but to inform the compiler to produce executable code for float, double, and long double
Well... if all your types are default constructible (as float, double and long double)... using folding in a template foo() function as follows
template <typename ... Ts>
void foo ()
{ ((calculate_a(Ts{}), calculate_b(Ts{}, Ts{})), ...); }
and calling foo() with desidered types
foo<float, double, long double>();
should work, I suppose.
The following is a full compiling example
template <typename T>
T calculate_a (T x)
{ return x; }
template <typename T>
T calculate_b (T x, T y)
{ return x+y; }
template <typename ... Ts>
void foo ()
{ ((calculate_a(Ts{}), calculate_b(Ts{}, Ts{})), ...); }
int main ()
{
foo<float, double, long double>();
}
Use regular overloading for the types you want and have them call the function template, as in:
float calculate_a(float x) { return calculate_a<float>(x); }
float calculate_b(float x, float y) { return calculate_b<float>(x, y); }
double calculate_a(double x) { return calculate_a<double>(x); }
double calculate_b(double x, double y) { return calculate_b<double>(x, y); }
long double calculate_a(long double x) { return calculate_a<long double>(x); }
long double calculate_b(long double x, long double y) { return calculate_b<long double>(x, y); }
Related
I have a templated function which accepts a function as a parameter, like
template <typename Function>
void apply(Function f) {
// do something that invokes f(...)
}
I want to constrain it so that the return type of f() must be some type, say int.
I do not want to constrain the parameters of f (e.g., assume it takes three ints as parameters).
Here's a naive solution, that combines std::enable_if_t, std::is_same_v, decltype and std::declval:
#include <type_traits>
template <
typename Function,
typename = std::enable_if_t<
std::is_same_v<
decltype(std::declval<Function>()(
std::declval<int>(),
std::declval<int>(),
std::declval<int>()
)),
int
>
>
>
void apply(Function f) {
f(1,2,3);
}
int foo(int x, int y, int z);
char bar(int x, int y, int z);
int main()
{
apply(foo);
apply(bar);
}
(live demo)
foo works but bar doesn't.
This should also behave as expected for alternative overloads of foo, because part of the machinery is specifying the types of the arguments we're going to provide to the Function.
Recently I am learning the template function in C++. I am wondering if there is any simple way for me to do the following thing.
For example, I have defined a template function in C++ as follow:
template <typename T, float t_p>
void func_a(T* input, T* output):
{
output = input / t_p;
}
Now, I want to define another template function based on this template function for f_p = 4.0. I know I may be able to do the following thing:
template <typename T>
void func_b(T* input, T* output):
{
func_a<T,4.0>(input, output);
}
but this code looks very heavy. Especially when I have many input variables. I am wondering if there is any way that I can do to be similar as follows
template <typename, T>
func_b = func_a<T , 4.0>;
If so, it will be very helpful
You can't do it with functions, but you can do it with functors. S.M. noted that you can't use float as a template non-type parameter, so let's replace it with int. I also suppose that you want to operate on values, not on pointers (either dereference pointers, or use references).
template<int t_p>
struct func_a
{
template<typename T>
void operator()(const T& input, T& output) const
{
output = input / t_p;
}
};
using func_b = func_a<4>;
using func_c = func_a<5>;
Now you can use these functors in the following way:
void foo()
{
int a = 100;
int b;
func_a<2>()(a, b);
func_b()(a, b);
func_c()(a, b);
}
Note that you need extra empty parentheses to create a functor.
If you want to use float you can do something like this:
struct func_a
{
func_a(float p) : p(p) { }
template<typename T>
void operator()(const T& input, T& output) const
{
output = input / p;
}
private:
const float p;
};
void foo()
{
const auto func_b = func_a(4);
const auto func_c = func_a(5);
float a = 100;
float b;
func_a(2)(a, b);
func_b(a, b);
func_c(a, b);
}
Maybe a little Off Topic but I give you a useful, I hope, little suggestion: switch the order of your template parameters.
I mean: write func_a() as follows (I use int for t_p because, as pointed by S.M., a float value can't a valid template parameter)
template <int t_p, typename T>
void func_a(T* input, T* output):
{ output = input / t_p; }
The point is that T can be deduced from the function arguments (input and output) where t_p can't be deduced so must be explicated.
If the order is T first and t_p second, you must explicate also T, so (by example) in func_b() you must write
func_a<T,4>(input, output);
If the order is t_p first and T second, you must explicate only t_p and you can let the compiler deduce the T type; so you can simply write
func_a<4>(input, output);
In this case is a little improvement but, in other circumstances, can be useful.
Say I use C++ type-traits in a method template to check if T is double, is there some way I can treat variables of type T as double, without doing a cast?
T *l_double; //T is double
if T is of type double
auto a = 5 * (*l_double);
(This will fail because T can be a non-number type, I could solve it by casting, but would like to avoid it).
If I understand your question correctly, what you want to have is a specialization for the case of T being double. Well, just do that - no type traits involved:
template <typename T>
void foo(T x) { /* do something with x */ }
template <>
void foo<double>(double x) { /* do something _else_ with x */ }
Or if you use C++17, you can also do:
template <typename T>
void foo(T x) {
if constexpr (not std::is_same_v<double,T>) {
/* do something with x */
}
else {
/* do something with else x */
}
}
Note the constexpr after the if. That means the code within each block only gets compiled for the appropriate instantiations; without it, you can't use x as a double in the else block since that use would have to also work when x is of another type.
In this example I create a Functor class taking functions as parameters. The second functor shall take an object of the first functor as template parameter and call a function of the first functor. I am not sure how the template for the second Functor must look.
This is the first Functor, which is working as expected:
typedef float (*pDistanceFu) (float, float);
typedef float (*pDecayFu) (float, float, float);
template <pDistanceFu Dist, pDecayFu Rad, pDecayFu LRate>
class DistFunction {
public:
DistFunction() {}
DistFunction(char *cstr) : name(cstr) {};
char *name;
float distance(float a, float b) { return Dist(a,b); };
float rad_decay(float a, float b, float c) { return Rad(a,b,c); };
float lrate_decay(float a, float b, float c) { return LRate(a,b,c); };
};
Here I create an instance of the functor which is specialized:
DistFunction<foo,bar,foobar> fcn_gaussian((char*)"gaussian");
Here I don't know how the template has to look, to take any type of DistFunction<...> as parameter
template<template<DistFunction> typename = F>
struct functor {
float fCycle;
float fCycles;
functor(float cycle, float cycles) : fCycle(cycle), fCycles(cycles) {}
float operator()(float lrate) {
return (F.lrate_decay)(lrate, fCycle, fCycles);
}
};
How I want to use the second functor:
typedef DistFunction<foo,bar,foobar> gaussian;
void test() {
functor<gaussian> test(0,1);
}
The errors:
error: argument list for class template "DistFunction" is missing
error: expected "class"
error: expected a "," or ">"
template<DistFunction> typename = F
This is an unnamed template template parameter with a single non-type parameter of type DistFunction and default value F. Since DistFunction is not a type (it's a class template) and F does not exist, this makes no sense.
You don't need any template template parameters here. The simple
template<typename F>
struct functor {
should do the job.
If you want to restrict F, that is, only allow it to accept various instantiations of DistFunction and nothing else, you need different language facilities, such as static_assert and/or enable_if. This is only needed for better error messages in case someone imstantiates functor incorrectly. Just use F as if it is a DistFunction.
Try
template<typename F>
struct functor {
float fCycle;
float fCycles;
functor(float cycle, float cycles) : fCycle(cycle), fCycles(cycles) {}
float operator()(float lrate) {
return F((char*)"gaussian").lrate_decay(lrate, fCycle, fCycles);
}
};
LIVE
NOTE: I added a similar but greatly simplified version of the problem at Ambiguous overload of functions like `msg(long)` with candidates `msg(int32_t)` and `msg(int64_t)`. That version has the advantage of a complete compilable example in a single file.
Problem
I have a C library with functions like
obj_from_int32(int32_t& i);
obj_from_int64(int64_t& i);
obj_from_uint32(uint32_t& i);
obj_from_uint64(uint64_t& i);
In this case the types int32_t etc are not the std ones - they are implementation defined, in this case an array of chars (in the following example I've omitted the conversion - it doesn't change the question which is about mapping intergral types to a particular function based on the number of bits in the integral type).
I have a second C++ interface class, that has constructors like
MyClass(int z);
MyClass(long z);
MyClass(long long z);
MyClass(unsigned int z);
MyClass(unsigned long z);
MyClass(unsigned long long z);
Note, I can't replace this interface with std::int32_t style types - if I could I wouldn't need to ask this question ;)
The problem is how to call the correct obj_from_ function based on the number of bits in the integral type.
Proposed Solutions
I'm putting two proposed solutions, since no killer solution has floated to the top of the list, and there are a few that are broken.
Solution 1
Provided by Cheers and hth. - Alf. Comments from this point on are my own - feel free to comment and/or edit.
Advantages
- Fairly simple (at least compared to boost::enable_if)
- Doesn't rely on 3rd party library (as long as compiler supports tr1)
*Disadvantages**
- If more functions (like anotherObj_from_int32 etc) are needed, a lot more code is required
This solution can be found below - take a look, it's nifty!
Solution 2
Advantages
Once the ConvertFromIntegral functions are done, adding new functions that need the conversion is trivial - simply write a set overloaded on int32_t, int64_t and unsigned equivalents.
Keeps use of templates to one place only, they don't spread as the technique is reused.
Disadvantages
Might be overly complicated, using boost::enable_if. Somewhat mitigated by the fact this appears in once place only.
Since this is my own I can't accept it, but you can upvote it if you think it's neat (and clearly some folks do not think it is neat at all, that's what downvote it for, I think!)
Thanks to everyone who contributed ideas!
The solution involves a conversion function from int, long and long long to int32_t and int64_t (and similar for the unsigned versions). This is combined with another set of functions overloaded on int32_t, int64_t and unsigned equivalents. The two functions could be combined, but the first conversion functions make a handy utility set that can be reused, and then the second set of functions is trivially simple.
// Utility conversion functions (reuse wherever needed)
template <class InputT>
typename boost::enable_if_c<sizeof(InputT)==sizeof(int32_t) && boost::is_signed<InputT>::value,
int32_t>::type ConvertFromIntegral(InputT z) { return static_cast<int32_t>(z); }
template <class InputT>
typename boost::enable_if_c<sizeof(InputT)==sizeof(int64_t) && boost::is_signed<InputT>::value,
int64_t>::type ConvertFromIntegral(InputT z) { return static_cast<int64_t>(z); }
template <class InputT>
typename boost::enable_if_c<sizeof(InputT)==sizeof(uint32_t) && boost::is_unsigned<InputT>::value,
uint32_t>::type ConvertFromIntegral(InputT z) { return static_cast<uint32_t>(z); }
template <class InputT>
typename boost::enable_if_c<sizeof(InputT)==sizeof(uint64_t) && boost::is_unsigned<InputT>::value,
uint64_t>::type ConvertFromIntegral(InputT z) { return static_cast<uint64_t>(z); }
// Overload set (mock implementation, depends on required return type etc)
void* objFromInt32 (int32_t i) { obj_from_int32(i); }
void* objFromInt64 (int64_t& i) { obj_from_int64(i); }
void* objFromUInt32(uint32_t& i) { obj_from_uint32(i); }
void* objFromUInt64(uint64_t& i) { obj_from_uint64(i); }
// Interface Implementation
MyClass(int z) : _val(objFromInt(ConvertFromIntegral(z))) {}
MyClass(long z): _val(objFromInt(ConvertFromIntegral(z))) {}
MyClass(long long z): _val(objFromInt(ConvertFromIntegral(z))) {}
MyClass(unsigned int z): _val(objFromInt(ConvertFromIntegral(z))) {}
MyClass(unsigned long z): _val(objFromInt(ConvertFromIntegral(z))) {}
MyClass(unsigned long long z): _val(objFromInt(ConvertFromIntegral(z))) {}
A simplified (single compilable .cpp!) version of the solution is given at Ambiguous overload of functions like `msg(long)` with candidates `msg(int32_t)` and `msg(int64_t)`
Given 3rd party functions …
void obj_from_int32( int32_bytes_t& i );
void obj_from_int64( int64_bytes_t& i );
void obj_from_uint32( uint32_bytes_t& i );
void obj_from_uint64( uint64_bytes_t& i );
you can call the "correct" such function for a built-in type as follows:
template< int nBytes, bool isSigned >
struct ThirdParty;
template<>
struct ThirdParty< 4, true >
{
template< class IntegralT >
static void func( IntegralT& v )
{ obj_from_int32( v ) } // Add whatever conversion is required.
};
// Etc., specializations of ThirdParty for unsigned and for 8 bytes.
template< class IntegralT >
void myFunc( IntegralT& v )
{ ThirdParty< sizeof( v ), std::is_signed< IntegralT >::value >::func( v ); }
Instead of overloading, what about pattern matching? Use boost::enable_if and a helper template to select the type of operation you're looking for?
Something like this:
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_integral.hpp>
#include <iostream>
template <typename T, typename Dummy=void> struct helper;
// Handle signed integers of size 1 (8 bits)
template <typename T> struct helper<T,
typename boost::enable_if_c<
boost::is_integral<T>::value &&
(sizeof(T)==1) &&
(static_cast<T>(-1) < static_cast<T>(0)) >::type>
{
static void do_stuff(T const& ) {std::cout<<"signed, size 1"<<std::endl;}
};
// Handle unsigned integers of size 1 (8 bits)
template <typename T> struct helper<T,
typename boost::enable_if_c<
boost::is_integral<T>::value &&
(sizeof(T)==1) &&
(static_cast<T>(-1) > static_cast<T>(0)) >::type>
{
static void do_stuff(T const& ) {std::cout<<"unsigned, size 1"<<std::endl;}
};
// Handle signed integers of size 2 (16 bits)
template <typename T> struct helper<T,
typename boost::enable_if_c<
boost::is_integral<T>::value &&
(sizeof(T)==2) &&
(static_cast<T>(-1) < static_cast<T>(0)) >::type>
{
static void do_stuff(T const& ) {std::cout<<"signed, size 2"<<std::endl;}
};
// And so on and so forth....
// Use a function for type erasure:
template <typename T> void do_stuff(T const& value)
{
helper<T>::do_stuff(value);
}
int main()
{
do_stuff(static_cast<unsigned char>(0)); // "unsigned, size 1"
do_stuff(static_cast<signed short>(0)); // "signed, size 2"
}
More complete listing (and proof it works with GCC at least) at http://ideone.com/pIhdq.
Edit: Or more simply, but with perhaps less coverage: (using the standard integral types)
template <typename T> struct helper2;
template <> struct helper2<uint8_t> {static void do_stuff2(uint8_t ) {...}};
template <> struct helper2<int8_t> {static void do_stuff2(int8_t ) {...}};
template <> struct helper2<uint16_t> {static void do_stuff2(uint16_t ) {...}};
template <> struct helper2<int16_t> {static void do_stuff2(int16_t ) {...}};
// etc.
template <typename T> void do_stuff2(T value) {helper2<T>::do_stuff2(value);}
As we discovered in linked problem, the long is cause of ambiguity here.
The line
MyClass(long z): _val(objFromInt(z)) {}
should be changed to something like:
MyClass(long z): _val(sizeof(long) == 4 ? static_cast<int32_t>(z) : static_cast<int64_t>(z)))) {}
Please note, that you will probably face similar problem with long long on 64-bit gcc.
As pointed out in other answers, this can be trivially solved at runtime using if(sizeof(int)==sizeof(int32_t)) style branches. To do this at compile-time, boost::enable_if can be used.
template <class InputT>
typename boost::enable_if_c<sizeof(InputT)==sizeof(int32_t) && boost::is_signed<InputT>::value,
int32_t>::type ConvertIntegral(InputT z) { return static_cast<int32_t>(z); }
template <class InputT>
typename boost::enable_if_c<sizeof(InputT)==sizeof(int64_t) && boost::is_signed<InputT>::value,
int64_t>::type ConvertIntegral(InputT z) { return static_cast<int64_t>(z); }
template <class InputT>
typename boost::enable_if_c<sizeof(InputT)==sizeof(uint32_t) && boost::is_unsigned<InputT>::value,
uint32_t>::type ConvertIntegral(InputT z) { return static_cast<uint32_t>(z); }
template <class InputT>
typename boost::enable_if_c<sizeof(InputT)==sizeof(uint64_t) && boost::is_unsigned<InputT>::value,
uint64_t>::type ConvertIntegral(InputT z) { return static_cast<uint64_t>(z); }
Anywhere you need to convert an integral type to an int32_t, int64_t, uint32_t or uint64_t simply call like:
ConvertIntegral(long(5)); // Will return a type compatible with int32_t or int64_t
The ConvertIntegral function can be combined with the int32_t and int64_t overload set for a complete solution. Alternatively, the technique illustrated could be built-in to the overload set.
Also, the above could be further enhanced by disabling for non-integral types. For a complete example of using the functions, see Ambiguous overload of functions like `msg(long)` with candidates `msg(int32_t)` and `msg(int64_t)`
An ambiguity can easily stem from overloading on both signed and unsigned types. For instance, given
void foo(unsigned int);
void foo(long);
then foo(0) is ambiguous as conversions (or maybe promotions) from int to both unsigned int and long are ranked the same.
Either pick one signedness, or write two overload sets for each signedness if you're using constructor overloads that use unsigned types (and you care about that).