I have a series of templated classes that I'd like to make aware of each other at compile-time. Each object may have other compile-time attributes that would be used to setup runtime conditions for the code.
My ideal pattern would be something like this:
template <unsigned int A, unsigned int B>
class FirstClass
{
};
template < template<unsigned int A, unsigned int B> FirstClass &firstClass >
class SecondClass
{
};
//...
FirstClass<1,2> fc;
SecondClass<fc> sc;
ThirdClass<sc> tc;
//...
Is there a way to do this?
I can get close if I do something like this for SecondClass:
template < unsigned int A, unsigned int B, FirstClass<A,B> &firstClass >
But this then requires me to pass the two extra arguments (rather than have the compiler infer them) and will not scale very well.
Thanks!
The right question is: do you really care if the argument of the second template is really from the first, or is it ok with you if it behaves exactly like the first template?
In the second case, there is really nothing to do. Simply use normal template argument.
In the first case, you can always use static_assert with is_same. It would require the first type to have constants for the two arguments:
template <unsigned int A, unsigned int B>
class FirstClass
{
public:
constexpr static unsigned int a = A;
constexpr static unsigned int b = B;
};
Then you can do:
template <typename FC>
class SecondClass
{
static_assert(std::is_same<FC,FirstClass<FC::a, FC::b> >::value, "Wrong template argument for SecondClass");
};
If you are not using C++11, look at the static_assert implementation in Boost, it is not that complex. And you will also have to implement yourself the is_same, but I don't know that is difficult.
And to use it:
FirstClass<1,2> fc;
SecondClass<decltype(fc)> sc;
Note that you will never be allowed to use a local variable at template argument.
Another thing you might want to look at (still C++11) is a helper function:
If you re-write your second class as:
template <unsigned int A, unsigned int B>
struct SecondClass
{
FirstClass<A,B> fc;
A(FirstClass<A,B> arg)
:fc(arg)
{ }
};
Then you can write:
template <unsigned int A, unsigned int B>
SecondClass<A,B> secondClass(FirstClass<A,B> arg)
{
return SecondClass<A,B>(arg);
}
And in you function:
FirstClass<1,2> fc;
auto sc = secondClass(fc)
I think C++11's decltype is what you're looking for. It will let you abstain from writing those template arguments over and over again.
It's important to note that in the example below, the pointer code in SecondClass is entirely unnecessary and I only included it because I wasn't sure whether your project needed runtime access. ThirdClass is the preferred example.
EDIT: I read your comment about arbitrary number of types. FourthClass or FifthClass here may be what you're looking for. It uses variadic templates, tuples, and some TMP code (for_each iterating over a tuple) from https://stackoverflow.com/users/680359/emsr in question iterate over tuple.
I hope there is enough here to get you started.
#include<iostream>
#include<tuple>
#include<string>
template <unsigned int A, unsigned int B>
struct FirstClass
{
static constexpr unsigned int C = A;
static constexpr unsigned int D = B;
};
template < typename T, const T* const t >
struct SecondClass
{
static constexpr unsigned int FOR_THIRD_CLASS = T::C;
//SecondClass knows about a FirstClass instance at compile time
static constexpr T* const pFirstClass = t;
//uses FirstClass values, which were computed at compile time, at runtime
void printFirstClassValues() const {
//ThirdClass below is an example without pointers or references, which it sounds like you don't need
std::cout << t -> C << " " << t -> D;
}
};
template < typename T >
struct ThirdClass
{
void printSecondClassValue() const {
std::cout << "\nIn ThirdClass method: " << T::FOR_THIRD_CLASS;
}
};
static constexpr FirstClass<1,2> fc;
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
for_each(std::tuple<Tp...> &, FuncT) // Unused arguments are given no names.
{ }
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
for_each(std::tuple<Tp...>& t, FuncT f)
{
f(std::get<I>(t));
for_each<I + 1, FuncT, Tp...>(t, f);
}
struct Functor
{
template<typename T>
void operator()(T& t) const { std::cout << t << ", "; }
};
template< typename... Ts >
struct FourthClass{
std::tuple< Ts... > myTuple;
//if you need it...
static constexpr int numberOfTypes = sizeof...(Ts);
FourthClass(Ts... pack):myTuple(pack...){
}
void print(){
for_each( myTuple, Functor() );
}
};
//maybe this is better - give it a tuple to begin with
template < typename my_tuple >
class FifthClass{
};
//just use your imagination here - these are ridiculous typedefs that don't ever make sense to use, I'm just showing you how to use FifthClass with a variable number of types
typedef SecondClass< decltype(fc), &fc > SC;
typedef ThirdClass<SC> TC;
typedef FourthClass<TC> FC;
typedef std::tuple<SC,TC,FC> ArbitraryClasses;
typedef std::tuple<SC,TC,FC,ArbitraryClasses> OtherArbitraryClasses;
typedef std::tuple<SC,TC,FC,ArbitraryClasses,OtherArbitraryClasses, int, std::string> MoreArbitraryClasses;
int main(){
SecondClass<decltype(fc), &fc> sc;
ThirdClass<decltype(sc)> tc;
sc.printFirstClassValues();
tc.printSecondClassValue();
std::cout << "\nEdit: here's a variadic example..." << std::endl;
FourthClass < int,unsigned int, short, const char*, int*, std::string > fourth(9,6,19,"this is a string", (int*)0xDEADBEEF, "I could keep going with any cout-able types");
fourth.print();
FifthClass < MoreArbitraryClasses > fifth;
return 0;
}
Related
I have class that takes two template arguments:
template< typename T, size_t Len >
struct A {
size_t GetLen() const {
return Len;
}
T mArr[Len];
};
typedef A< int, 10 > IntArrOfTenLen;
typedef A< int, 5 > IntArrOfTenFive;
So far so good. Now I want to write a function that can do something with such typedef'd variables. Something like this:
void f(_arr)
{
std::cout << _arr[_arr.GetLen() - 1];
}
void g()
{
IntArrOfTenLen arr;
IntArrOfTenFive arr2;
f(arr);
f(arr2);
}
Is it possible? What should be the signature of such function f()?
I have tried following:
template< typename A >
void f(A _arr) {
std::cout << _arr[_arr.GetLen() - 1];
}
This fails because Len is not provided, but that providing Len will be kind of defeating the purpose of writing GetLen(), isn't it?
If you want f to take As of arbitrary type and length, make it a template function:
template <typename T, size_t Len>
void f(const A<T,Len>& arr) {
//...
}
You don't need to supply T and Len with this template; they'll be deduced from the argument:
f(arr) //f<int, 10>
f(arr2) //f<int, 5>
Of course, instead of reinventing the wheel, you could just use std::array in C++11 rather than writing your own.
This question is related to one on SO a couple of years ago by Georg Fritzsche about transforming a parameter pack (Is it possible to transform the types in a parameter pack?). In the end, the individual types in the parameter pack can be transformed, e.g. by converting to corresponding pointer types.
I am wondering if it is possible to use this technique to write one standard function/functor and a set of wrapper functions (out of one template), so that the wrappers can take parameters of equivalent types and then call the standard function to do actual work.
Using the answer by Johannes Schaub - litb the original example below. Is it possible to write one template f, which can take any combinations of int/int*,char/char* and call a common function f_std(int*,char*) to do the work. (The number of parameters is not pre-specified.)
--- Update ---
For example, given int i; char c;, is it possible to write a caller using pack transformation such that the following works
call_ptr(f_std,i,c);
call_ptr(f_std,&i,c);
call_ptr(f_std,i,&c);
What I've tried so far is listed below (updated to clarify.). Basically, I tried to accept an list of not necessarily pointer types and convert them to pointer types, before making call to a std::function that takes pointer types. But the code does not compile. I don't know how to write a helper function to accept one function with a standard signature, but accept a parameter pack of something else.
Thanks in advance
#include <type_traits>
#include <functional>
using namespace std;
template<class... Args> struct X {};
template<class T> struct make_pointer { typedef T* type; };
template<class T> struct make_pointer<T*> { typedef T* type; };
template<template<typename...> class List,
template<typename> class Mod,
typename ...Args>
struct magic {
typedef List<typename Mod<Args>::type...> type;
};
/////////////////
// trying to convert parameter pack to pointers
template<class T> T* make_ptr(T x) { return &x; }
template<class T> T* make_ptr(T* x) { return x; }
template <typename Value, typename ...Args>
class ByPtrFunc
{
public:
typedef typename magic<X, make_pointer, Args...>::type PArgs;
Value operator()(Args... args) { return f(make_ptr(args)...); }
private:
std::function<Value (PArgs...)> _ptr_func;
}; //ByPtrFunc
//helper function to make call
template<typename A, typename ...Args>
static A call_ptr(std::function<A (Args...)> f, Args... args) {
return ByPtrFunc<A, Args...>{f}(args ...);
}
int main() {
typedef magic<X, make_pointer, int*, char>::type A;
typedef X<int*, char*> B;
static_assert(is_same<A, B>::value, ":(");
int i=0; char c='c';
function<int (int* pa,char* pb)> f_std = [](int* pa,char* pb)->int {return *pa + * pb;};
f_std(&i,&c);
//////////////////
//Is the following possible.
call_ptr(f_std,i,c);
call_ptr(f_std,&i,c);
call_ptr(f_std,i,&c);
return 0;
}
This answers your question syntax-wise, if I've understood it correctly: yes, it's possible.
// given int or char lvalue, returns its address
template<class T>
T* transform(T& t) {
return &t;
}
// given int* or char*, simply returns the value itself
template<class T>
T* transform(T* t) {
return t;
}
// prints out the address corresponding to each of its arguments
void f_std() {
}
template<class Arg, class... Args>
void f_std(Arg arg, Args... args) {
std::cout << (void*)arg << std::endl;
f_std(args...);
}
// converts int to int*, char to char*, then calls f_std
template<class... Args>
void f(Args... args) {
f_std(transform(args)...);
}
Unfortunately, calling f will pass int and char arguments by value, and hence copy them. To fix this, use perfect forwarding in the definition of f:
template<class... Args>
void f(Args&&... args) {
f_std(transform(std::forward<Args>(args))...);
}
Driver:
int main() {
int x = 1;
char c = 'a';
cout << (void*)&x << endl;
cout << (void*)&c << endl;
f(x, &x, c, &c);
}
Output (example; ran it on my machine just now):
0x7fff36fb5ebc
0x7fff36fb5ebb
0x7fff36fb5ebc
0x7fff36fb5ebc
0x7fff36fb5ebb
0x7fff36fb5ebb
Following may help:
template <typename T> T* make_pointer(T& t) { return &t; }
template <typename T> T* make_pointer(T* t) { return t; }
template <typename Ret, typename... Args, typename ...Ts>
Ret call_ptr(std::function<Ret (Args*...)> f, Ts&&...args)
{
static_assert(sizeof...(Args) == sizeof...(Ts), "Bad parameters");
f(make_pointer(std::forward<Ts>(args))...);
}
Now, use it:
void f_std(int*, char*) { /* Your code */ }
int main(int argc, char *argv[])
{
int i;
char c;
std::function<void (int*, char*)> f1 = f_std;
call_ptr(f1, i, c);
call_ptr(f1, i, &c);
call_ptr(f1, &i, c);
call_ptr(f1, &i, &c);
return 0;
}
For reference, below is what worked for me, based on the accepted answer #Jarod42 and the type transformation "magic". slightly more general and with added type checking. Turns out type-transformation is simply a pattern expansion.
#include <type_traits>
#include <functional>
#include <iostream>
using namespace std;
/////////////////
// convert parameter pack to pointers
//types
template<class T> struct make_ptr_t { typedef T* type; };
template<class T> struct make_ptr_t<T*> { typedef T* type; };
//values
template<class T> T* make_ptr(T& x) { return &x; }
template<class T> T* make_ptr(T* x) { return x; }
/////////////////////////////////////
// (optional) only for type checking
template<class... Args> struct X {};
template<template<typename...> class List,
template<typename> class Mod,
typename ...Args>
struct magic {
typedef List<typename Mod<Args>::type...> type;
};
//helper function to make call
template<typename A, typename ...PArgs, typename ...Args>
static A call_ptr(std::function<A (PArgs...)> f, Args... args) {
static_assert(is_same<X<PArgs...>,typename magic<X, make_ptr_t, Args...>::type>::value, "Bad parameters for f in call_ptr()"); //type checking
return f(make_ptr(args)...);
}
int main() {
int i=0; char c='c'; string s="c";
function<int (int* pa,char* pb)> f_std = [](int* pa,char* pb)->int {return *pa + * pb;};
f_std(&i,&c);
cout << call_ptr(f_std,i,c) << endl;
cout << call_ptr(f_std,&i,c) << endl;
cout << call_ptr(f_std,i,&c) << endl;
//cout << call_ptr(f_std,i,s) << endl; //complains about bad parameters.
return 0;
}
Suppose I have a std::tuple made up of types like
struct A {
static void tip();
};
struct B {
static void tip();
};
struct Z {
};
std::tuple<const A&,const B&,const Z&> tpl;
Yes, I need separate A, B. (The implementation of ::tip() differs for each type.) What I try to implement is a type-sensitive "visitor" that iterates through the tuple starting from the beginning to the end. Upon visiting a particular element of type T a function should be called depending on whether T has the ::tip() method or not. In the simple example of above only A and B have ::tip() implemented and Z not. So, the iterator should call twice the function for types with the ::tip() method and once the other function.
Here is what I came up with:
template< int N , bool end >
struct TupleIter
{
template< typename T , typename... Ts >
typename std::enable_if< std::is_function< typename T::tip >::value , void >::type
static Iter( const T& dummy , const std::tuple<Ts...>& tpl ) {
std::cout << "tip\n";
std::get<N>(tpl); // do the work
TupleIter<N+1,sizeof...(Ts) == N+1>::Iter( std::get<N+1>(tpl) , tpl );
}
template< typename T , typename... Ts >
typename std::enable_if< ! std::is_function< typename T::tip >::value , void >::type
static Iter( const T& dummy , const std::tuple<Ts...>& tpl ) {
std::cout << "no tip\n";
std::get<N>(tpl); // do the work
TupleIter<N+1,sizeof...(Ts) == N+1>::Iter( std::get<N+1>(tpl) , tpl );
}
};
template< int N >
struct TupleIter<N,true>
{
template< typename T , typename... Ts >
static void Iter( const std::tuple<Ts...>& tpl ) {
std::cout << "end\n";
}
};
I use a dummy instance of the type of the element at the iterator position and decide via enable_if which function to call. Unfortunately this doesn't work/isn't a nice solution:
The compiler complains about recursive instantiation
The const T& dummy is not a clean solution
I was wondering if enable_if is the right strategy to do the decision and how can one recursively iterate through the std::tuple capturing the first type and keeping all the remaining arguments in vital state. Read through How to split a tuple? but it doesn't do any decision.
How can one implement such a thing in a correct and portable way in C++11?
Well, it was harder than I expected, but this works.
Some things you were doing wrong/that I modified:
You can't evaluate this: std::is_function< typename T::tip >::value, since T::tip is not a type. Even if this could be evaluated, what would happen when T::tip does not exist? Substitution would still fail.
Since you use const references as your tuple's inner types, you had to clean them before trying to find the tip member inside them. By cleaning I mean removing const and removing the reference.
That dummy type stuff was not a good idea, there was no need to use that parameter. You can achieve the same thing using std::tuple_element, which retrieves the i-th type from a tuple.
I modified TupleIter's template parameters to the following, which means:
"TupleIter that processes the index-th type, inside a tuple of size n".
template<size_t index, size_t n>
struct TupleIter;
The whole code is this:
#include <tuple>
#include <iostream>
#include <type_traits>
struct A {
static void tip();
};
struct B {
static void tip();
};
struct Z {
};
// Indicates whether the template parameter contains a static member named tip.
template<class T>
struct has_tip {
template<class U>
static char test(decltype(&U::tip));
template<class U>
static float test(...);
static const bool value = sizeof(test<typename std::decay<T>::type>(0)) == sizeof(char);
};
// Indicates whether the n-th type contains a tip static member
template<size_t n, typename... Ts>
struct nth_type_has_tip {
static const bool value = has_tip<typename std::tuple_element<n, std::tuple<Ts...>>::type>::value;
};
// Generic iteration
template<size_t index, size_t n>
struct TupleIter
{
template< typename... Ts >
typename std::enable_if< nth_type_has_tip<index, Ts...>::value , void >::type
static Iter(const std::tuple<Ts...>& tpl)
{
std::cout << "tip\n";
TupleIter<index + 1, n>::Iter(tpl );
}
template< typename... Ts >
typename std::enable_if< !nth_type_has_tip<index, Ts...>::value , void >::type
static Iter(const std::tuple<Ts...>& tpl) {
std::cout << "no tip\n";
TupleIter<index + 1, n>::Iter(tpl );
}
};
// Base class, we've reached the tuple end
template<size_t n>
struct TupleIter<n, n>
{
template<typename... Ts >
static void Iter( const std::tuple<Ts...>& tpl ) {
std::cout << "end\n";
}
};
// Helper function that forwards the first call to TupleIter<>::Iter
template<typename... Ts>
void iterate(const std::tuple<Ts...> &tup) {
TupleIter<0, sizeof...(Ts)>::Iter(tup);
}
int main() {
A a;
B b;
Z z;
std::tuple<const A&,const B&,const Z&> tup(a,b,z);
iterate(tup);
}
Here is another take on the question, very similar to mfontanini answer, but showcasing:
boost::fusion::for_each (instead of manually iterate over the tuple).
A variant for implementing has_type using an expression-based SFINAE approach, that I feel a little bit simpler to follow than the usual sizeof trick.
#include <boost/tuple/tuple.hpp>
#include <boost/fusion/include/boost_tuple.hpp>
#include <boost/fusion/algorithm.hpp>
#include <iostream>
struct nat // not a type
{
private:
nat();
nat(const nat&);
nat& operator=(const nat&);
~nat();
};
template <typename T>
struct has_tip
{
static auto has_tip_imp(...) -> nat;
template <typename U>
static auto has_tip_imp(U&&) -> decltype(U::tip());
typedef decltype(has_tip_imp(std::declval<T>())) type;
static const bool value = !std::is_same<type, nat>::value;
};
struct CallTip
{
template<typename T>
typename std::enable_if<has_tip<T>::value>::type
operator()(T& t) const
{
std::cout << "tip\n";
T::tip();
}
template<typename T>
typename std::enable_if<!has_tip<T>::value>::type
operator()(T& t) const
{
std::cout << "no tip\n";
return;
}
};
struct A {
static void tip(){}
};
struct B {
static void tip(){}
};
struct Z {
};
int main()
{
A a;
B b;
Z z;
boost::tuple<const A&,const B&,const Z&> tpl(a, b, z);
boost::fusion::for_each(tpl, CallTip());
}
Note that if your compiler support variadic template you can use std::tuple instead of boost::tuple inside fusion::for_each by including #include<boost/fusion/adapted/std_tuple.hpp>
Edit :
As pointed by Xeo in the comment, it is possible to simplify a lot the expression-SFINAE approach by removing completely the trait has_tip and simply forward to a little call helper.
The final code is really neat and tight !
#include <boost/tuple/tuple.hpp>
#include <boost/fusion/include/boost_tuple.hpp>
#include <boost/fusion/algorithm.hpp>
#include <iostream>
struct CallTip
{
template<typename T>
void operator()(const T& t) const
{
call(t);
}
template<class T>
static auto call(const T&) -> decltype(T::tip())
{
std::cout << "tip\n";
T::tip();
}
static void call(...)
{
std::cout << "no tip\n";
}
};
struct A {
static void tip(){}
};
struct B {
static void tip(){}
};
struct Z {
};
int main()
{
A a;
B b;
Z z;
boost::tuple<const A&,const B&,const Z&> tpl(a, b, z);
boost::fusion::for_each(tpl, CallTip());
}
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 );
}
I'm trying to use templates to unroll a loop in C++ as follows.
#include <iostream>
template< class T, T i >
struct printDown {
static void run(void) {
std::cout << i << "\n";
printDown< T, i - 1 >::run();
}
};
template< class T >
struct printDown< T, 0 > {
static void run(void) {
std::cout << 0 << "\n";
}
};
int main(void) {
printDown< int, 10 >::run();
return 0;
}
When I compile w/ g++ 3.4.4 in Cygwin, I get the following error.
tmp.cpp:12: error: type T' of
template argument0' depends on
template parameter(s)
What am I doing wrong? Do I need to somehow annotate the 0 to say that it's of type T?
Thanks in advance.
Have you tried int i instead of T i?
Why this happens? From 14.5.5/8,
— The type of a template parameter
corresponding to a specialized
non-type argument shall not be
dependent on a parameter of the
specialization. [ Example:
template <class T, T t> struct C {};
template <class T> struct C<T, 1>; // error
template< int X, int (*array_ptr)[X] > class A {};
int array[5];
template< int X > class A<X,&array> { }; // error
—end example ]
Therefore when you apply partial specialization, the type of 0 is T (dependent on a parameter of the specialization). There are two choices, one is to make it none dependent, e.g., change T i to int i, and second is to apply explicit specialization rather than partial specialization.
Both solutions have been given out by others, so I'm not gonna to repost them here. At least you know the reason. It's defined by standard.
As pointed out by phooji your implementation suffers from a small issue: it quickly generates a long list of calls, which will make compilers choke quickly.
You could work around this by implementing a slightly more complicated version, using binary decomposition. I'll make it generic on a functor too, cause I am lazy.
// Signature
template <Functor F, unsigned N>
struct UnrolledLoop;
We need a helper template, which keeps an offset of the parameter to pass
template <Functor F, unsigned N, unsigned OffSet>
struct UnrolledImpl;
template <Functor F, unsigned OffSet>
struct UnrolledImpl<F, 0, OffSet>
{
static F run(F f) { return f; }
};
template <Functor F, unsigned OffSet>
struct UnrolledImpl<F, 1, OffSet>
{
static F run(F f) { f(OffSet); return f; }
};
template <Functor F, unsigned N, unsigned OffSet>
struct UnrolledImpl
{
static F run(F f) {
F f2 = UnrolledImpl<F, N/2, OffSet>::run(f);
return UnrolledImpl<F, N - N/2, OffSet + N/2>::run(f2);
}
};
And you can implement UnrolledLoop simply:
template <Functor F, unsigned N>
struct UnrolledLoop
{
static F run(F f) { return UnrolledImpl<F, N, 0>::run(f); }
}
Note that you could provide specialization for more values of N (3, 4 for example) to be nicer on the compiler.
What about adding this to your example:
template struct printDown< int, 0 >{
static void run(void) {
std::cout << 0 << "\n";
} };
The compiler cannot cast 0 to int automatically without knowing T's type in advance.
Just found this out. Apparently one can do something like this.
template< class T, T i, bool b = (i == 0) >
struct printDown {
static void run(void) {
std::cout << i << "\n";
printDown< T, i - 1 >::run();
}
};
template< class T, T i >
struct printDown< T, i, true > {
static void run(void) {
std::cout << 0 << "\n";
}
};
I had no idea that could be done. Very Prologish & very nice.
You can make the parameter a type parameter to work this around
template< bool > struct bool_ { };
template< class T, T i, typename = bool_<true> >
struct printDown {
static void run(void) {
std::cout << i << "\n";
printDown< T, i - 1 >::run();
}
};
template< class T, T i >
struct printDown< T, i, bool_<i == 0> > {
static void run(void) {
std::cout << 0 << "\n";
}
};
int main(void) {
printDown< int, 10 >::run();
return 0;
}
This way you can specify any conditions you want in the partial specializations.