【问题标题】:Mixing template function overloading and inheritance混合模板函数重载和继承
【发布时间】:2010-12-06 22:44:18
【问题描述】:

以下代码打印:

generic
overload

但我想要的是在这两种情况下都调用了重载或专业化,而不是通用的。我不想将重载与模板专业化混为一谈,它们在一起是因为没有一个能像我预期的那样工作。有没有什么模板魔法可以做到这一点?

#include <iostream>

class Interface {};
class Impl: public Interface {};

class Bar
{
public:
    template<typename T> void foo(T& t) {
        std::cout << "generic\n";
    }
    void foo(Interface& t) {
        std::cout << "overload\n";
    }
};
template<> void Bar::foo<Interface>(Interface& t) {
    std::cout << "specialization\n";
}

int main() {
    Bar bar;
    Impl impl;
    Interface& interface = impl;
    bar.foo(impl);
    bar.foo(interface);
    return 0;
}

【问题讨论】:

    标签: c++ templates inheritance


    【解决方案1】:

    使用type_traits 测试参数是否从接口派生的两种方法。

    #include <boost/type_traits.hpp>
    
    class Interface {};
    class Impl: public Interface {};
    
    class Bar
    {
        template <class T> void foo_impl(T& value, boost::false_type)
        {
            std::cout << "generic\n";
        }
        void foo_impl(Interface& value, boost::true_type)
        {
            std::cout << "Interface\n";
        }
    public:
        template<typename T> void foo(T& t) {
            foo_impl(t, boost::is_base_of<Interface, T>());
        }
    
    };
    

    或者如果满足条件就禁用模板,只留下非模板作为候选。

    #include <boost/utility/enable_if.hpp>
    #include <boost/type_traits.hpp>
    
    class Interface {};
    class Impl: public Interface {};
    
    class Bar
    {
    public:
        template<typename T>
        typename boost::disable_if<boost::is_base_of<Interface, T>, void>::type foo(T& t)
        {
            std::cout << "generic\n";
        }
    
        void foo(Interface&)
        {
            std::cout << "Interface\n";
        }
    };
    

    【讨论】:

      【解决方案2】:

      为了使用专用函数,编译器需要将参数从&amp;Impl 转换为&amp;Interface。当它在寻找函数签名匹配时,完全匹配比需要转换的更优先。由于泛型 foo&lt;T&gt; 是完全匹配的,因此它胜过重载和专用函数。

      【讨论】:

        【解决方案3】:

        模板定义允许创建函数:

        void Bar::foo<Impl>(Impl& t)
        

        这比您定义的带有Interface&amp; 参数的匹配更好。

        你必须让超类函数更好地匹配,可能是这样的:

        class Bar
        {
            struct fallback { fallback(int) {} };
            template<typename T> void foo(T& t, fallback) {
                std::cout << "generic\n";
            }
            void foo(Interface& t, int) {
                std::cout << "overload\n";
            }
        public:
            template<typename T> void foo(T& t) {
                foo(t, 0);
            }
        };
        

        但似乎并没有真正起作用,请参阅http://ideone.com/IpBAv

        所以你需要在通用版本中进行类型测试,寻找Interface 的子类。

        【讨论】:

        • 当我第一次查看该代码时,我认为它格式错误,原因与 GCC 认为它格式错误的原因相同。但是再想一想,我认为这应该解决非模板,因为如果其他一切都相等,非模板函数比函数模板特化更好
        • @Johannes:你知道解决办法吗?
        • 不,请忽略我上面的评论:这不是真的,因为“如果其他一切都相同”应该说“如果非模板对其任何参数都没有更差的转换,并且模板没有更好地转换其任何参数”。所以正如我的第一条评论所说,这 is 纵横交错:stackoverflow.com/questions/3519282/why-is-this-ambiguity-here/…,GCC 是正确的。
        • 我试过ideone.com/ZRHfa,但我认为这是一个不可推断的上下文,所以模板根本不再工作。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-20
        • 2014-11-11
        • 1970-01-01
        • 1970-01-01
        • 2023-04-04
        • 1970-01-01
        相关资源
        最近更新 更多