功能模板的模糊重载

时间:2014-08-01 12:30:09

标签: c++ templates overloading

这个(人为的)代码:

#include <iostream>

template<typename T> class Foo
{
public:
    Foo(int i) : i_(i) {}

private:
    int i_;
};

template<typename T>
Foo<T> bar(const T& /*x*/, const Foo<T>& /*foo*/)
{
    std::cout << "first bar()" << std::endl;
    return Foo<T>(1);
}

template<typename T>
Foo<T> bar(int /*x*/, const Foo<T>& /*foo*/)
{
    std::cout << "second bar()" << std::endl;
    return Foo<T>(42);
}

int main()
{
    Foo<bool> f1(0);
    Foo<bool> f2 = bar(true, f1); // first bar()
    Foo<bool> f3 = bar(10, f1); // second bar()
    (void)f2; // avoid warning for unused variable
    (void)f3; // avoid warning for unused variable
    return 0;
}

做得不多,但用g ++ 4.7.2编译好:

$ g++ -std=c++11 -Wall -Wextra foo.cpp

并产生预期结果:

$ ./a.out 
first bar()
second bar()

当我在bool中将模板类型从int更改为main()时:

int main()
{
    Foo<int> f1(0);
    Foo<int> f2 = bar(true, f1); // first bar()
    Foo<int> f3 = bar(10, f1); // second bar()
    (void)f2; // avoid warning for unused variable
    (void)f3; // avoid warning for unused variable
    return 0;
}

我收到编译错误:

$ g++ -std=c++11 -Wall -Wextra foo.cpp 
foo.cpp: In function 'int main()':
foo.cpp:30:29: error: call of overloaded 'bar(int, Foo<int>&)' is ambiguous
foo.cpp:30:29: note: candidates are:
foo.cpp:13:8: note: Foo<T> bar(const T&, const Foo<T>&) [with T = int]
foo.cpp:20:8: note: Foo<T> bar(int, const Foo<T>&) [with T = int]

问题是bar()的两个版本在这种情况下都会发生冲突,编译器无法决定选择哪个版本。

怎么能解决这个问题?

3 个答案:

答案 0 :(得分:1)

标签调度:

struct selector {};

template<typename T>
Foo<T> bar(const T& /*x*/, const Foo<T>& /*foo*/, const selector&)
{
    std::cout << "first bar()" << std::endl;
    return Foo<T>(1);
}

// call it
bar(1, f1, selector{});

这只是一个例子,假设更多的重载,需要更复杂。

正如Johan正确指出的那样,enable_if仅适用于模板方法。

答案 1 :(得分:1)

您可以使用struct的部分模板特化,例如:

namespace detail
{
    template <typename T1, typename T2> struct bar;

    template <typename T> struct bar<T, T>
    {
        Foo<T> operator()() const
        {
            std::cout << "first bar()" << std::endl;
            return Foo<T>(1);
        }
    };

    template <typename T> struct bar<int, T>
    {
        Foo<T> operator()() const
        {
            std::cout << "second bar()" << std::endl;
            return Foo<T>(42);
        }
    };

    template <> struct bar<int, int>
    {
        Foo<int> operator()() const
        {
            std::cout << "third bar()" << std::endl;
            return Foo<int>(42);
        }
    };

}


template<typename T1, typename T2>
Foo<T2> bar(const T1& /*x*/, const Foo<T2>& /*foo*/)
{
    return detail::bar<T1, T2>()();
}

用以下方法测试:

int main()
{
    Foo<int> f1(0);
    Foo<int> f2 = bar<int>(true, f1); // first bar()
    Foo<int> f3 = bar(10, f1); // second bar()
    (void)f2; // avoid warning for unused variable
    (void)f3; // avoid warning for unused variable
    return 0;
}

int main()
{
    Foo<bool> f1(0);
    Foo<bool> f2 = bar(true, f1); // first bar()
    Foo<bool> f3 = bar(10, f1); // second bar()
    (void)f2; // avoid warning for unused variable
    (void)f3; // avoid warning for unused variable
    return 0;
}

答案 2 :(得分:0)

如果你可以使用参数选择选项,你可以选择你想要使用哪个栏,这可以消除歧义。我希望这可以帮助。

#include <iostream>

template<typename T> class Foo
{
public:
    Foo(int i) : i_(i) {}

private:
    int i_;
};

template<typename T>
Foo<T> bar(const T& /*x*/, const Foo<T>& /*foo*/,int pick=0)
{
    std::cout << "first bar()" << std::endl;
    return Foo<T>(1);
}

template<typename T>
Foo<T> bar(int /*x*/, const Foo<T>& /*foo*/,double pick=0)
{
    std::cout << "second bar()" << std::endl;
    return Foo<T>(42);
}

int main()
{
    Foo<bool> f1(0);
    Foo<int> f15(0);
    Foo<bool> f2 = bar(true, f1); // first bar()
    Foo<int> f3 = bar(10, f15,1); // first bar()
    Foo<int> f35 = bar(10, f15,1.0); // second bar()
    (void)f2; // avoid warning for unused variable
    (void)f3; // avoid warning for unused variable
    return 0;
}