C++ 模板分支 [英] C++ Template Branching

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

问题描述

我有一个有趣的案例,试图在模板函数中创建分支,其中路径依赖于模板类型实现的接口.这个分支然后确定返回值的构造函数.我不确定这种类型的分支是否可能.另一种方法是将函数拆分为两个不同的函数,并让用户调用对应于所需分支的函数.

I have an interesting case of trying to have branch within a template function where the path is dependent on the interface implemented by the template type. This branch then determines the constructor of the return value. I am unsure if this type of branching is possible. The alternative it to split the function into two different function and have the user call the one that corresponds to the desired branch.

我的问题有两个:

如何根据接口实现执行if语句?

当接口没有实现时,如何让函数进行编译?例如int没有带两个参数的构造函数.

How can I get the function to compile when the interface is not implemented? For example int does not have a constructor with two parameters.

template<typename T>
T GetObject()
{
    // If T implements interface, call interface constructor
    if(typeid(T) implements inteface IInterface) // How can this be done?
        return T(1, 2);

    // If T does not implement the interface, call parameterless constructor
    else
        return T();
}

推荐答案

正如您可以轻松推断出的那样,您的代码无法正常工作(即使我希望这样做),因为无论您在 if 语句中放入什么, 每一行都必须被编译——即使有些会在优化过程中被删除.即使你有正确的行:

As you can easily deduce, your code as is has no way of working (even though I wish it did) because regardless of what you put in your if statements, every line has to be compiled - even if some will later be removed during optimization. Even if you had the correct line for:

if(typeid(T) implements inteface IInterface)
    return T(1,2); // <---

第二行仍然会为 int 编译,这是不好的.

The second line would still be compiled for int, which is no good.

您想要的是 SFINAE:替换失败不是错误.基本上,您故意编写一个无法编译的声明,但只要有一个可以编译的可用重载,那就足够了!所以为此,我们只是利用了一些类型特征和魔法,但非常简单,enable_if:

What you want is SFINAE: Substitution Failure Is Not An Error. Basically, you intentionally write a declaration that cannot compile but as long as there's an available overload that will compile, that's good enough! So to that end, we just take advantage of some type traits and the magic, yet incredibly simple, enable_if:

// this overload will only exist if T is-a IInterface
template<typename T>
typename std::enable_if<
    std::is_base_of<IInterface, T>::value,
    T
>::type
GetObject() {
    return T(1,2);
}

// this overload will only exist if T is NOT an IInterface
template<typename T>
typename std::enable_if<
    !std::is_base_of<IInterface, T>::value,
    T
>::type
GetObject() {
    return -1;
}

// explicit for int - put this *last*
// due to complications with specialization
template <>
int GetObject() {
    return 0;
}

尽管考虑到 Herb Sutter 的文章关于函数专业化,使用重载可能更好:

Although given Herb Sutter's article on function specialization, probably better to use overloading:

template <typename T> struct empty_ { };

template <typename T>
T GetObject() { return GetObjectImpl(empty_<T>{} ); }

// the int version: overload, not specialization
int GetObjectImpl( empty_<int> ) { 
    return 0;
}

// the other two versions are the same as before
template <typename T>
typename std::enable_if<... same as before ...>::type
GetObjectImpl(empty_<T> ) {
    return T(1,2);
}

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

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