Вопрос

I'm trying to specialize a member function template for two different types of classes as follows:

#include <iostream>
#include <boost/utility/enable_if.hpp>

struct Wibble
{
    static const bool CAN_WIBBLE = true;
};

struct Wobble
{
    static const bool CAN_WIBBLE = false;
};

struct Foo
{
    //template<typename T>   // Why isn't this declaration sufficient?
    //void doStuff();

    template<typename T>
    typename boost::enable_if_c<T::CAN_WIBBLE,void>::type
    doStuff();

    template<typename T>
    typename boost::enable_if_c<!T::CAN_WIBBLE,void>::type
    doStuff();  
};

template<typename T>
typename boost::enable_if_c<T::CAN_WIBBLE,void>::type
Foo::doStuff()
{
    std::cout << "wibble ..." << std::endl;
}

template<typename T>
typename boost::enable_if_c<!T::CAN_WIBBLE,void>::type
Foo::doStuff()
{
    std::cout << "I can't wibble ..." << std::endl;
}

int main()
{
    Foo f;
    f.doStuff<Wibble>();
    f.doStuff<Wobble>();
}

Whereas GCC 4.8.2 compiles the code, VS .NET 2008 spits out the error message:

error C2244: 'Foo::doStuff' : unable to match function definition to an existing declaration

        definition
        'boost::enable_if_c<!T::CAN_WIBBLE,void>::type Foo::doStuff(void)'
        existing declarations
        'boost::enable_if_c<!T::CAN_WIBBLE,void>::type Foo::doStuff(void)'
        'boost::enable_if_c<T::CAN_WIBBLE,void>::type Foo::doStuff(void)'
Это было полезно?

Решение

I suggest to use tag dispatching: https://ideone.com/PA5PTg

struct Foo
{
    template<bool wibble>
    void _doStuff();

public:
    template<typename T>
    void doStuff()
    {
        _doStuff<T::CAN_WIBBLE>();
    }
};

template<>
void Foo::_doStuff<true>() { std::cout << "wibble ..." << std::endl; }

template<>
void Foo::_doStuff<false>() { std::cout << "I can't wibble ..." << std::endl; }

Другие советы

You can't partially specialize (member) function templates. End of story.

Even if you could, you should have had a SFINAE-friendly primary template. In pseudo code:

template<typename T, typename Enable> void doStuff();
template<typename T> void doStuff<T, typename boost::enable_if_c<T::CAN_WIBBLE,void>::type>()
    { std::cout << "wibble ..." << std::endl; }
template<typename T> void doStuff<T, typename boost::enable_if_c<!T::CAN_WIBBLE,void>::type>()
    { std::cout << "I can't wibble ..." << std::endl; }

You could still use this technique if you are ready class templates (as functors or just types defining non-template methods...).

As a rule of thumb, for function templates, overload resolution provides static polymorphism that removes the need for partial specialization. See

Both by Herb Sutter

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top