Frank - 8 months ago 39

C++ Question

I have an SFINAE problem:

In the following code, I want the C++ compiler to pick the specialized functor and print "special", but it's printing "general" instead.

`#include <iostream>`

#include <vector>

template<class T, class V = void>

struct Functor {

void operator()() const {

std::cerr << "general" << std::endl;

}

};

template<class T>

struct Functor<T, typename T::Vec> {

void operator()() const {

std::cerr << "special" << std::endl;

}

};

struct Foo {

typedef std::vector<int> Vec;

};

int main() {

Functor<Foo> ac;

ac();

}

How can I fix it so that the specialized struct is used automatically? Note I don't want to directly specialize the

`Functor`

`Foo`

`Vec`

P.S.: I am using g++ 4.4.4

Answer Source

Sorry for misleading you in the last answer, I thought for a moment that it would be simpler. So I will try to provide a complete solution here. The general approach to solve this type of problems is to write a *traits* helper template and use it together with `enable_if`

(either C++11, boost or manual implementation) to decide a class specialization:

**Trait**

A simple approach, not necessarily the best, but simple to write would be:

```
template <typename T>
struct has_nested_Vec {
typedef char yes;
typedef char (&no)[2];
template <typename U>
static yes test( typename U::Vec* p );
template <typename U>
static no test( ... );
static const bool value = sizeof( test<T>(0) ) == sizeof(yes);
};
```

The approach is simple, provide two template functions, that return types of different sizes. One of which takes the nested `Vec`

type and the other takes ellipsis. For all those types that have a nested `Vec`

the first overload is a better match (ellipsis is the worst match for any type). For those types that don't have a nested `Vec`

SFINAE will discard that overload and the only option left will be the ellipsis. So now we have a trait to ask whether any type has a nested `Vec`

type.

**Enable if**

You can use this from any library, or you can roll your own, it is quite simple:

```
template <bool state, typename T = void>
struct enable_if {};
template <typename T>
struct enable_if<true,T> {
typedef T type;
};
```

When the first argument is `false`

, the base template is the only option, and that does not have a nested `type`

, if the condition is `true`

, then `enable_if`

has a nested `type`

that we can use with SFINAE.

**Implementation**

Now we need to provide the template and the specialization that will use SFINAE for only those types with a nested `Vec`

:

```
template<class T, class V = void>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
template<class T>
struct Functor<T, typename enable_if<has_nested_Vec<T>::value>::type > {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
```

Whenever we instantiate `Functor`

with a type, the compiler will try to use the specialization, which will in turn instantiate `has_nested_Vec`

and obtain a truth value, passed to `enable_if`

. For those types for which the value is `false`

, `enable_if`

does not have a nested `type`

type, so the specialization will be discarded in SFINAE and the base template will be used.

**Your particular case**

In your particular case, where it seems that you don't really need to specialize the whole type but just the operator, you can mix the three elements into a single one: a `Functor`

that dispatches to one of two internal templated functions based on the presence of `Vec`

, removing the need for `enable_if`

and the traits class:

```
template <typename T>
class Functor {
template <typename U>
void op_impl( typename U::Vec* p ) const {
std::cout << "specialized";
}
template <typename U>
void op_impl( ... ) const {
std::cout << "general";
}
public:
void operator()() const {
op_impl<T>(0);
}
};
```