Sign in to follow this  
soconne

C++ templates and conditional code generation

Recommended Posts

I'm have a class template and I would like to test whether one of the type parameters is a pointer or not.
template <class T>
class Test {
    if T is a pointer then generate
        void set(T* value) { }
    else
        void set(const T& value) { }
};


Is there a way to do this? I've thought about attempting it using template specialization, but how do you determine within the template, if a parameter is a pointer or not? **EDIT** I've come up with the following way using template specialization but its kind of ugly.
template <class T, bool isPointer=false>
class Test {
public:
	T m_var;
};

template <class T>
class Test<T, true> {
public:
	T* m_var;
};

Is there a better way?

Share this post


Link to post
Share on other sites
template <typename T>
class Test
{
typedef typename boost::mpl::if_<boost::is_pointer<T>::value, T*, const T&>::type parameter_type;

void set(parameter_type value)
{
}
};



Namespaces might be wrong here or there, but that's what you're looking for.

Edit: Removed 'typename' before boost::is_pointer<T>::value (not a type!)

Share this post


Link to post
Share on other sites
If you don't want to use boost, this should work:


template <typename T>
class Kitten
{
public:
void set(const T& t) { cout << "const ref version: " << t << "\n"; }
};

template <typename T>
class Kitten <T*>
{
public:
void set(T *t) { cout << "pointer version: " << *t << "\n"; }
};



then:


Kitten <int> whiskers;
whiskers.set(5);

Kitten <int *> fluffy;
int value = 10;
fluffy.set(&value);

Share this post


Link to post
Share on other sites
Quote:
Original post by PiNtoS
If you don't want to use boost, this should work:


Hey thanks PiNtoS. That's pretty much what I was going for.

But I also like the example _goat showed using boost. Although if at all possible I'd like not to use boost. I took a look at the boost header file containing the if_ template, it doesn't make a lot of sense, but I would ultimately like something similar to that.

Share this post


Link to post
Share on other sites
Well in case anybody was interested, I figured out how to implement is_pointer and fi_ using template specialization, which freakin rocks!


template <class T>
struct is_pointer {
enum { value = false };
};

template <class T>
struct is_pointer<T*> {
enum { value = true };
};

template <bool condition, class T1, class T2>
struct if_ { };

template <class T1, class T2>
struct if_<true, T1, T2> {
typedef T1 type;
};

template <class T1, class T2>
struct if_<false, T1, T2> {
typedef T2 type;
};


template <typename T>
class Test {
public:
typedef typename if_<is_pointer<T>::value, T*, const T&>::type parameter_type;

void set(parameter_type value) {

}
};

Share this post


Link to post
Share on other sites
Quote:
Original post by soconne
Quote:
Original post by PiNtoS
If you don't want to use boost, this should work:


Hey thanks PiNtoS. That's pretty much what I was going for.

But I also like the example _goat showed using boost. Although if at all possible I'd like not to use boost. I took a look at the boost header file containing the if_ template, it doesn't make a lot of sense, but I would ultimately like something similar to that.


Don't avoid Boost. It has a ton of extremely useful functionality. Install it, and use the bits you find convenient. There's usually no reason not to.

However, in this particular case, I'd say using boost's type_traits is overkill. As shown above, it's simple enough to make a template specialization for pointers.

But seriously, "I'd like not to use boost" is just silly. You might as well say you'd rather avoid functions, or loops. C++ without boost is just silly. [grin]
It's one of the few things that make C++ bearable.

Share this post


Link to post
Share on other sites
Yes I would definitely agree. Its just that I have not grown accustomed to boost's syntax and like you said, I only really need a single header file from it for type_traits.

Share this post


Link to post
Share on other sites
I've run into another slight problem. When I declare a property that's a pointer, I have no direct access to the -> operator. For instance:

class Test {
public:
property<MyClass*> class;
};

Test t;
t.class-> // this throws an error

Hence I have to overload the -> operator like so inside of the property template class.

ValueType operator->() const {
return getter();
}

ValueType is MyClass* in this case. My problems is that I don't want this function generated for a non-pointer type. So declaring property<MyClass> would not generate it. But I also do not want to have template specialization. Is there a way to accomplish this similar to the type traits method I used above for function parameters?

Hence, I want the overloaded operator -> function generated for a pointer type property, but not for a non-pointer type property, and I want the compile time condition within a single property class.

Share this post


Link to post
Share on other sites
Quote:
Original post by soconne
I've run into another slight problem. When I declare a property that's a pointer, I have no direct access to the -> operator. For instance:[...]
If you want Class<T> and Class<T*> to be different, you want template specialization as PiNtoS showed. If there is a lot of shared code between the various specializations, make a non-specialized property_base class that all the specialized property templates derive from.

Share this post


Link to post
Share on other sites
Quote:
Original post by Extrarius
Quote:
Original post by soconne
I've run into another slight problem. When I declare a property that's a pointer, I have no direct access to the -> operator. For instance:[...]
If you want Class<T> and Class<T*> to be different, you want template specialization as PiNtoS showed. If there is a lot of shared code between the various specializations, make a non-specialized property_base class that all the specialized property templates derive from.


Thanks! I hadn't thought of deriving them from a base class.

Share this post


Link to post
Share on other sites
I just changed my property class to property_base and then created the following class.


template <typename ValueType>
class property : public property_base<ValueType> {

};



So it basically doesn't have any special methods yet. But when I declared an integer property like so:

property<int> myInt;

And then call:

myClassObject.myInt = 10;

I get the following error:

error C2679: binary '=' : no operator found which takes a right-hand operand of type 'int' (or there is no acceptable conversion)

If I change property<int> to property_base<int> it works, no error. Anybody know why this is?

Share this post


Link to post
Share on other sites
Parent constructors and operator= can not be used directly by others.

The only property<int>::operator= you have is the default operator=(const property<int>& other), which copies all members and calls property_base<int>::operator=(const property_base<int>& base_other).

You have to implement

property<T>& property<T>::operator=(const T& value)
{
property_base<int>::operator=(value);
return *this;
}

and the same for the constructors, if you need some non-default-autogenerated.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this