模板专业化和C ++中的派生类 [英] Template specialization and derived classes in C++

查看:133
本文介绍了模板专业化和C ++中的派生类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个简单的代码:

class A{};
class B : public A{};
class C : public B{};

class Test
{
    public:
        template<typename T>
        void f(T&){printf("template\n");}
        void f(A&){printf("specialization\n");}
};

int main()
{
    A a;
    B b;
    C c;

    Test test;
    test.f(a);
    test.f(b);
    test.f(c);
}



当我运行它(VS2010)时,我有这个输出:

When I run it(VS2010) I have this output:

specialization
template
template

是否可以使用 A派生类调用以使用特殊化?

Is it possible to make the calls with A-derived classes to use specialization?

推荐答案

是的,这是可能的,但你必须更改你的代码。

Yes, it is possible, but you have to change your code a bit.

首先,为了技术性,第二个函数 f()模板函数的专门化,但 overload 。当解析重载时,为类型不是 A 的所有参数选择模板版本,因为它是完美匹配: T 被推导为等于参数的类型,因此当调用 f(b)时,例如,在类型推导之后,编译器将必须在以下选项之间进行选择两个重载:

First of all, to be technical, the second function f() is not a specialization of the template function, but an overload. When resolving overload, the template version is chosen for all arguments whose type is not A, because it is a perfect match: T is deduced to be equal to the type of the argument, so when calling f(b), for instance, after type deduction the compiler will have to choose between the following two overloads:

void f(B&){printf("template\n");}
void f(A&){printf("specialization\n");}

第一个是更好的匹配。

现在,如果你想要使用一个参数调用函数时选择第二个版本,该参数是 A ,您必须使用一些SFINAE技术来防止函数模板在类型 T 被推断为子类时被正确实例化 A

Now if you want the second version to be selected when the function is invoked with an argument which is a subclass of A, you have to use some SFINAE technique to prevent the function template from being correctly instantiated when the type T is deduced to be a subclass of A.

您可以使用 std :: enable_if 结合 std :: is_base_of 类型特征来实现。

You can use std::enable_if in combination with the std::is_base_of type traits to achieve that.

// This will get instantiated only for those T which are not derived from A
template<typename T,
    typename enable_if<
        !is_base_of<A, T>::value
        >::type* = nullptr
    >
void f(T&) { cout << "template" << endl; }

以下是在完整程序中使用它的方法:

Here is how you would use it in a complete program:

#include <type_traits>
#include <iostream>

using namespace std;

class A{};
class B : public A{};
class C : public B{};
class D {};

class Test
{
    public:

        template<typename T,
            typename enable_if<!is_base_of<A, T>::value>::type* = nullptr
            >
        void f(T&) { cout << ("template\n"); }

        void f(A&){ cout << ("non-template\n");}

};

int main()
{
    A a;
    B b;
    C c;
    D d;
    float f;

    Test test;
    test.f(a); // Will print "non-template"
    test.f(b); // Will print "non-template"
    test.f(c); // Will print "non-template"
    test.f(d); // Will print "template"
    test.f(f); // Will print "template"
}

如果您使用的编译器不完全符合C ++ 11(因此不支持函数模板上的默认模板参数),您可能需要更改 f()的模板重载的定义如下:

If you are working with a compiler which is not fully compliant with C++11 (and therefore does not support default template arguments on function templates), you might want to change the definition of your template overload of f() as follows:

template<typename T>
typename enable_if<!is_base_of<A, T>::value, void>::type 
f(T&) { cout << ("template\n"); }

程序的行为将是相同的。注意,如果 f()的返回类型是 void ,则可以忽略 enable_if 类模板。

The behavior of the program will be identical. Note that if the return type of f() is void, you can omit the second argument to the enable_if class template.

这篇关于模板专业化和C ++中的派生类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆