Vuwox
Vuwox

Reputation: 2359

Template function enable if with template only

Based on the following templated struct, used as pixel accessor.

template<class T, std::size_t N>
struct PixelAccessor
{   
    T ch[N];
};

using pxUChar_C1 = PixelAccessor<unsigned char, 1>;
using pxUChar_C3 = PixelAccessor<unsigned char, 3>;
using pxUChar_C4 = PixelAccessor<unsigned char, 4>;

using pxFloat_C1 = PixelAccessor<float, 1>;
using pxFloat_C3 = PixelAccessor<float, 3>;
using pxFloat_C4 = PixelAccessor<float, 4>;

// etc. for all other types (int, short, ushort, ...)

I made the following function to work only with uchar and float pixel that are 3 channels.

template<typename T, typename = typename std::enable_if<std::is_same<T, pxUChar_C3>::value || std::is_same<T, pxFloat_C3>::value>::type>
bool function(Image img) {
     // where getData is uchar*, and cast to T** allow 2D accessing
    auto imgPtr = (T**)img->getData();
}

Is there a way to do the following, or anything similar ? I would like to enable all 3 channels pixel, what ever there type is ?

template<typename T, typename = typename std::enable_if<std::is_base_of< PixelAcessor<std::any, 3>,T>::value>::type>

I would like to have a C++11 solution, but if there is a need of a newer compiler, Im open to solution and see what I do.

Upvotes: 1

Views: 90

Answers (3)

Vuwox
Vuwox

Reputation: 2359

As pointed in the comments, the usage of a wildcard such as std::any is not possible in template.

But after discussion, the usage of the template like I asked was a bit foolish, since I want to always use the T as a PixelAccessor itself, so it possible to use it differently such as I only template the T for the PixelAccessor itself.

template<typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value>::type>
bool function(Image img) {

    // Sanity check
    if(img->getNbChannels() != 3) return false;

    // where getData is uchar*, and cast to T** allow 2D accessing
    auto imgPtr = (PixelAccessor<T, 3>**)img->getData();
}

Upvotes: 0

NathanOliver
NathanOliver

Reputation: 181068

To get the function to take any PixelAccessor where N is 3 then you don't need enable_if and SFINAE. Just using

template<typename T>
return_type function_name(PixelAccessor<T, 3> parameter_name)
{
    // stuff
}

will give you a function that takes a PixelAccessor of any type and has a size of 3.

Upvotes: 5

You can use a custom channel extraction meta-function:

template<typename> struct GetPixelAccessorChannel
{ static constexpr std::size_t value = 0; }; 

template<typename T, std::size_t N> struct GetPixelAccessorChannel<PixelAccessor<T, N>>
{ static constexpr std::size_t value = N; }; 

Now it's a simple matter of testing the proper condition in the enable_if:

template<typename T, typename = typename std::enable_if<GetPixelAccessorChannel<T>::value == 3>::type>
bool function();

And as an aside, I'd rethink (T**)img->getData() in your stead. Needing such a cast looks very fishy to me.

Upvotes: 1

Related Questions