c++ - 使用 C++ 模板时表达约束

标签 c++ templates template-argument-deduction

我有一个 Wrapper 类。任何 T 或从 T 派生的对象都应可转换为此 Wrapper。

我还希望“SomeClass”的任何对象或从“SomeClass”派生的对象都可以转换为 Wrapper。两种情况下的实现都需要分开。我怎样才能做到这一点?

以下是我想要的行为:

class SomeClass;

template <typename T>
class Wrapper
{
public:

    Wrapper(const T & val)
    {

    }

    template <typename E>
    Wrapper(const E & val)
    {
        static_assert(std::is_base_of<T, E>::value,"Wrapped object needs to be of type T or a type derived from T");

        // Some implementation
    }
    // Is it possible to combine the above 2 constructors into a single 
    // one? That would help too...

    // Can't use SomeClass directly as type because in case of derived
    // type of SomeClass, I want the exact type for downstream processing 
    // into another template call
    template <typename E> // ??
    Wrapper(const E & val)
    {
        static_assert(std::is_base_of<SomeClass, E>::value,"Wrapped object needs to be of type SomeClass or a type derived from SomeClass");

        // another implementation
    }
};

不确定我是否能够正确表达我的问题。非常感谢任何帮助...

最佳答案

让我们从您当前拥有的功能不起作用的原因开始。模板函数(构造函数也是如此)由它们的签名标识。该签名包括模板参数是什么(类型、非类型、模板)、它们的顺序,以及函数参数和返回类型(构造函数没有返回类型,但这与我们要尝试的无关)完成)。所以你试图做的,涉及两次声明同一个构造函数!在考虑定义之前,您有一个重复的声明,这当然是不允许的。

那我们能做什么呢?我们可以为每个构造函数添加参数。如果它能区分它们,它们就可以共存。但是共存是不够的,我们希望重载决议能够区别对待它们。我们希望为从 T 派生的类选择第一个模板化的 c'tor。第二个为从 SomeClass 派生的类选择。我们能做到吗?我们可以。如果我们将要添加的模板参数设置为取决于我们的条件,并且在不满足条件时替换失败,则该重载将从考虑中移除。那是 SFINAE !

因此,将所有这些付诸实践:

template <typename E, std::enable_if_t<!std::is_same<SomeClass,T>::value &&
                                        std::is_convertible<E*, T*>::value>* = nullptr>
Wrapper(const E & val)
{
}

template <typename E, std::enable_if_t<std::is_convertible<E*, SomeClass*>::value>* = nullptr>
Wrapper(const E & val)
{

}

那么上面的内容是做什么的呢?它添加了另一个带有默认参数的模板参数。它是有条件地这样做的,如果在替换期间不满足条件,则“坏”c'tor 的签名是错误的。并且不会在重载决议中考虑。

我也冒昧地调整了你的条件。您可能只想接受公开派生自 TSomeClass 的类。 std::is_convertible 更好地表达了这一点。 std::is_base_of 也将允许私有(private)和不明确的多重继承。我还确保在 TSomeClass 的情况下,我们不会再得到两个冲突的构造函数声明。

关于c++ - 使用 C++ 模板时表达约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53039561/

相关文章:

c++ - SFINAE 仅启用从派生类到基类的强制转换运算符

c++ - 说编译器可以用值 1 替换下面的表达式 `a->i` 是正确的,因为......?

c++ - 如何解析PE文件不使用API

c++ - 如何为类定义 UUID,并以与 g++ 和 Visual C++ 相同的方式使用 __uuidof?

c++ - freopen 在我的应用程序关闭之前不会写入数据

c++ - C++ 中的非类型模板参数可以使用大括号初始值设定项吗?

c++ - 传递 const 类型地址时模板参数推导失败

c++ 模板参数匹配 std::function 与函数指针

c++ - 错误 LNK2019 未解析的外部符号 "public: __thiscall SLinkList<char>::SLinkList<char>(void)"

c++ - 可变参数推导指南不是由 g++ 采用,由 clang++ 采用 - 谁是正确的?