简体   繁体   中英

Boost enable/disable_if function pair's order matters?

I'm writing a recursive function whose end condition is determined by template parameters. I'm using boost::enable_if and boost::disable_if to switch out the recursive function for an empty base case (to prevent that tiresome infinite instantiation loop).
The problem is that it seems to depend on the order which I define these functions:

    #include <boost/utility.hpp>

    template <unsigned a, unsigned b>
    typename boost::disable_if_c<a == b>::type f()
    {
        f<a+1,b>();
    }

    template <unsigned a, unsigned b>
    typename boost::enable_if_c<a == b>::type f()
    {
    }

    int main()
    {
        f<0,5>();
    }

the compiler (g++4.6) fails with the error:

    test.cpp:7:5: error: no matching function for call to ‘f()’
    test.cpp:7:5: note: candidate is:
    test.cpp:5:44: note: template<unsigned int a, unsigned int b> typename boost::disable_if_c<(a == b)>::type f()

for some reason there's only the disabled function as a candidate, the enabled one isn't seen.

If I switch the order the two functions are defined it compiles with issue and without warnings:

    #include <boost/utility.hpp>

    template <unsigned a, unsigned b>
    typename boost::enable_if_c<a == b>::type f()
    {
    }

    template <unsigned a, unsigned b>
    typename boost::disable_if_c<a == b>::type f()
    {
        f<a+1,b>();
    }

    int main()
    {
        f<0,5>();
    }

Why is this? By the time the instantiation happens (in main ) the compiler has seen both functions and shouldn't care who got in line first. At least that's what I thought.

You say

By the time the instantiation happens (in main) the compiler has seen both functions and shouldn't care who got in line first.

This is not true and I think that's what's tripping you up. What's instantiated in main is just f<0,5> , the rest of instantiations happen where you call them, inside first f function template. The second one isn't visible from there so it can't participate in overload resolution.

So, what happens:

// imagine we're inside f<4,5> instantiation

template <unsigned a, unsigned b>
typename boost::disable_if_c<a == b>::type f()
{
    f<a+1,b>(); // <-- here we attempt to instantiate f<5,5> ...
                // but it gets disabled!

    // and there is no other f visible here, it's defined just below
}

If you switch the order of definitions, the enable_if version is visible and it kicks in when needed.

You're getting mixed up by fact that your functions are templates. That doesn't have anything to do with it. The following also doesn't compile, and for the same reason.

void foo(int)
{
  foo("");
}

void foo(char const*)
{
}

int main()
{
  foo(42);
}

Order matters.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM