繁体   English   中英

候选模板被忽略:无法推断模板参数

[英]Candidate template ignored: couldn't infer template argument

第一:错误信息确实如此给出。 在“论证”这个词后面只有引号,这本身就很奇怪。 但这是我试图解决的问题。 我正在编写一个内部存储(模板)类型引用的类,并且还应该接受可转换类型:

template<typename T>
class Ref {
public:
    Ref();
    Ref(std::nullptr_t);
    explicit Ref(T *value);

    Ref(Ref const& value);

    template<typename T2, typename std::enable_if<std::is_convertible<T2*, T*>::value, T2>::type>
    Ref(Ref<T2> const& value);

    template<typename T2, typename std::enable_if<std::is_convertible<T2*, T*>::value, T2>::type>
    Ref(Ref<T2> &&value);
private:
  T *_value;
};

现在我有2个A和B类:

class A {
};

class B : public A {
};

我正在尝试将B的Ref实例分配给A类的Ref变量:

Ref<B> t;
Ref<A> t2(t);

这实际上应该编译,但我得到了最后2个构造函数(那些采用可转换类型)的上述错误(clang),这实际上应该为该赋值启动。 需要做些什么来使模板参数推导在这里工作?

您错误地使用std::enable_if ,这应该是1 2

template<typename T2,
         typename = 
             typename std::enable_if<std::is_convertible<T2*, T*>::value>::type>
Ref(Ref<T2> const& value);

这里,如果T2*不能转换为T1* ,那么第二个模板参数默认为失败的东西,这就是你想要的:

  • 如果std::is_convertible<T2*, T*>::valuetrue ,那么这相当于:
template<typename T2, typename = void> // Ok, well-formed
Ref(Ref<T2> const& value);
  • 否则,你得到:
template<typename T2, typename = /* Something ill-formed */>
Ref(Ref<T2> const& value);

在原始代码中,当std::enable_if成功时,您的模板等效于:

template<typename T2, typename T2> // Well-formed, but T2 cannot be deduced
Ref(Ref<T2> const& value);

这不是你想要的(编译器在这种情况下无法推断出两个T2 )。

1如果可以访问C ++ 14,则可以使用std::enable_if_t<>替换typename std::enable_if<>::type

2这是一种可能性,另一种是使用std::enable_if_t<..., int> = 0 (或类似的东西),但我更喜欢typename = ...的版本。 它们在一般情况下并不完全相同,但在这种精确的情况下它并不重要。

@ Holt的答案很好,并且正确地解释了你应该如何使用std::enable_if

无论如何,在这种情况下,您根本不需要使用它。
static_assert就足够了,错误消息会更好用:

template<typename U>
Ref(Ref<U> const& value) {
    static_assert(std::is_convertible<U, T>::value, "!");
    // whatever you want 
}

template<typename U>
Ref(Ref<U> &&value) {
    static_assert(std::is_convertible<U, T>::value, "!");
    // whatever you want 
}

现在,这样的事情(其中C不能转换为A ):

Ref<A> t3(Ref<C>{});

会给你一个这样的错误:

错误:静态断言失败:! static_assert(std :: is_convertible :: value,“!”);

Sfinae表达式通常用于(让我说) 启用或禁用选择
如果您没有一组有效的替代方法可以从中选择正确的方法,则通常更static_assert

要完成Holt的答案,请注意您可以通过nullptr_t将默认构造函数和构造函数nullptr_tRef(std::nullptr_t = nullptr):_value{nullptr} {}

Ref(Ref const& value); 相当于Ref(Ref<T2> const& value); T2=T

你的代码段错过了operator= 使用复制和交换习惯用法 ,您可以使用它来稍微分解T2上的测试:

template<typename T>
class Ref {
public:
    Ref(std::nullptr_t = nullptr):_value{nullptr} {}
    explicit Ref(T *value);

    template<typename T2, typename = typename std::enable_if<std::is_convertible<T2*, T*>::value, T2>::type>
    Ref(Ref<T2> const& value);

    template<typename T2>
    Ref(Ref<T2> &&value):Ref{}
    {
        swap(*this, value);
    }

    template<typename T2>
    Ref& operator=(Ref<T2> value)
    {
        swap(*this, value);
        return (*this);
    }

    template<typename T1, typename T2, typename = typename std::enable_if<std::is_convertible<T2*, T1*>::value>::type>
    friend void swap(Ref<T1>& t1, Ref<T2>& t2)
    {
        using std::swap;
        swap(t1._value, t2._value);
    }
private:
  T *_value;
};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM