C++ 如何使用SFINAE仅为合适的类型启用特定的std::initializer\u list构造函数

C++ 如何使用SFINAE仅为合适的类型启用特定的std::initializer\u list构造函数,c++,c++14,sfinae,C++,C++14,Sfinae,下面你可以找到一个精简的、可复制的例子,说明我正在努力实现的目标。我的用例是一个自定义容器类模板。该类有一个构造函数,采用元素类型的std::initializer\u list。对于容器包含类型为std::unique\u ptr的元素的情况,我希望启用另一个构造函数,该构造函数采用std::initializer\u listakastd::initializer\u list。我的方法是在容器类的元素类型没有名为指针的类型的情况下,使用SFINAE禁用该构造函数,根据我对下面列出的示例的理

下面你可以找到一个精简的、可复制的例子,说明我正在努力实现的目标。我的用例是一个自定义容器类模板。该类有一个构造函数,采用元素类型的
std::initializer\u list
。对于容器包含类型为
std::unique\u ptr
的元素的情况,我希望启用另一个构造函数,该构造函数采用
std::initializer\u list
aka
std::initializer\u list
。我的方法是在容器类的元素类型没有名为
指针
的类型的情况下,使用SFINAE禁用该构造函数,根据我对下面列出的示例的理解,这应该是一个有效的SFINAE失败案例,并且没有编译错误


我无法理解为什么编译器在这里选择新的唯一ptr重载,据我所知,
std::complex
没有名为
指针的公共类型

您只缺少一个细节

SFINAE仅在即时上下文上可用,该上下文不包括类中的模板参数。只有方法中的模板参数

解决此问题的一种方法是在方法中使用一个额外的模板参数,该参数默认为
T

template <typename U = T, typename OwnedTypePtr = typename U::pointer>
MyVector (std::initializer_list<typename U::pointer> il)
{
    vector.reserve (il.size());
    for (auto* ptr : il)
        vector.emplace_back (ptr);
}
模板
MyVector(std::初始值设定项\u列表il)
{
vector.reserve(il.size());
用于(自动*ptr:il)
vector.emplace_back(ptr);
}

在这里,当我们以无效的方式使用
U
时,SFINAE将起作用。

初始值设定项列表中放置
unique\U ptr
是毫无意义的,因为您只有
const
访问其成员的权限;你不能离开它们。我不是想把
unique\u ptr
放在
initializer\u列表中,我是想把
unique\u ptr
的底层类型的指针放在列表中谢谢-完全忽略了这一点。虽然乍一看这是可行的,但我现在在T=std::complex方面遇到了麻烦。根据that@PluginPenguin啊,对。我们不能在参数中使用
OwnedTypePtr
,因为这将允许扣除我们传入的内容,在这种情况下,模板参数的默认值将被忽略。如果我们将其替换为
typename U::pointer
,我们将得到正确的行为。这是我通常使用非类型模板参数来执行SFINAE的原因之一。如果我们想用不同的SFINAE重载多个模板构造函数,这甚至是必需的。变得有点冗长。啊,当然,我明白了。。。这完全有道理。
type 'int' cannot be used prior to '::' because it has no members
in instantiation of template class 'MyVector<int>' requested here
    MyVector<int> v { 0, 1, 2 };

#include <vector>
#include <memory>
#include <complex>

template <typename T>
struct MyVector
{
    /** General initializer list constructor */
    MyVector (std::initializer_list<T> il) : vector (il) {}

    /** Constructor for the case MyVector<std::unique_ptr<SomeType>>. 
        Should be treated as an SFINAE failure for non unique_ptr types 
    */
    template <typename U = T, typename OwnedTypePtr = typename U::pointer>
    MyVector (std::initializer_list<OwnedTypePtr> il)
    {
        vector.reserve (il.size());
        for (auto* ptr : il)
            vector.emplace_back (ptr);
    }

    std::vector<T> vector;
};

template <typename T>
using UniqueVector = MyVector<std::unique_ptr<T>>;

int main()
{
    UniqueVector<int> uv { new int (0), new int (1), new int (2) };
    MyVector<std::complex<int>> v { 0, 1, 2 };

    return 0;
}
template <typename U = T, typename OwnedTypePtr = typename U::pointer>
MyVector (std::initializer_list<typename U::pointer> il)
{
    vector.reserve (il.size());
    for (auto* ptr : il)
        vector.emplace_back (ptr);
}