繁体   English   中英

SFINAE模板专业化优先级

[英]SFINAE template specialization precedence

#include <iostream>
#include <array>
#include <vector>

template <typename T, typename SFINAE=void>
struct trait;

template <typename T>
struct trait<T, decltype(
  std::declval<const T&>().begin(),
  std::declval<const T&>().end(),
  void()
)> {
  static const char* name() { return "Container"; }
};

template <typename T, std::size_t N>
struct trait<std::array<T,N>> {
  static const char* name() { return "std::array"; }
};

int main(int argc, char* argv[]) {
  std::cout << trait<std::vector<int>>::name() << std::endl;
  std::cout << trait<std::array<int,2>>::name() << std::endl;
}

我期待第三个模板比第二个模板更专业,但我得到了一个模糊的模板实例化

有没有办法让第三个模板更专业? 明确检查T是否是第二个模板中的std::array对我不起作用。 我正在编写一个库,希望用户能够定义自己的trait专长。 第二个模板旨在成为没有更具体特征的容器的通用特化。

#include <iostream>
#include <array>
#include <vector>

template <typename T, typename SFINAE=void>
struct trait;

template <typename T>
struct trait<T, std::void_t<decltype(std::declval<T>().begin()),
decltype(std::declval<T>().end())>> {
  static const char* name() { return "Container"; }
};

template <typename T, std::size_t N>
struct trait<std::array<T,N>,void> {
  static const char* name() { return "std::array"; }
};

int main(int argc, char* argv[]) {
  std::cout << trait<std::vector<int>>::name() << std::endl;
  std::cout << trait<std::array<int,2>>::name() << std::endl;
}

编辑

首先,不能保证跟随它真正更多的猜测而不是证明。 也许其他人可以纠正,扩展复制粘贴或其他任何东西。

然而,在看到问题后我的第一个猜测是使用std::void_t 我很确定我以前见过这样的东西,但是也不能保证。 为了表明可以使用std::void_t我们必须证明“一个模板特化比另一个更具体”。 我们通过检查部分订单来完成此操作。 我将模仿上面的内容,下面的内容有点简短。

template <typename T, typename SFINAE=void>
struct trait;
//#1
template <typename T>struct trait<T, std::void_t<decltype(std::declval<T>().begin())>>
{
  static const char* name() { return "Container"; }
};
//#2
template <typename T>struct trait<std::vector<T>,void> {
  static const char* name() { return "std::vector"; }
};

我不打算解释如何完成部分排序,需要太长时间。 在转换为函数等之后......最终得到类似于以下内容的东西。

//#2 from #1: f(trait<std::vector<T>,void>) from f(trait<__ANY_TYPE__, std::void_t<decltype(std::declval<__ANY_TYPE__>().begin())>)
    //P=trait<std::vector<T>,void>
    //A=trait<__ANY_TYPE__, std::void_t<decltype(std::declval<__ANY_TYPE__>().begin())>>
        //P1=std::vector<T>
        //A1=__ANY_TYPE__
        //P2=void
        //A2=std::void_t<decltype(std::declval<__ANY_TYPE__>().begin())>
        //==> T=? --> fail, #2 from #1 is not working

现在我们必须证明#2中的#1正在运行。 如果是这样,我们已经表明#2更专业。

//#1 from #2: f(trait<T, std::void_t<decltype(std::declval<T>().begin())>>) from f(trait<std::vector<__ANY_TYPE__>,void>)
    //P=trait<T, std::void_t<decltype(std::declval<T>().begin())>>
    //A=trait<std::vector<__ANY_TYPE__>,void>
        //P1=T
        //A1=std::vector<__ANY_TYPE__>
        //P2=std::void_t<decltype(std::declval<T>().begin())> //(*)
        //A2=void
        //==> T=std::vector<__ANY_TYPE__> ok #1 from #2 works

这基本上是我的草图,没有检查标准或其他任何东西。 我很确定你可以在标准的无穷无尽的路线中找到它......

如果你注意了,你会注意到(*)。 如果你想使用decltype(...),这一行基本上是唯一重要的一行。 我的猜测是使用decltype(...)导致右侧的非推导上下文,这可能不允许使用P1 / A1推论中的T. 但是,这基本上是我没有首先在工作std::void_t解决方案中包含答案的原因。 最后,使用typename部分的替代std::void_t定义是因为typename部分,我认为非推导的上下文就像decltype(...)一样。


编辑

只是添加一些最后一行。 原则上,对于脱落型sfinae应该没有问题。 好吧,它的非推断上下文,但为什么它是一个问题? 我唯一能想到的是,非演绎语境与部分排序相结合有一些特殊规则......

暂无
暂无

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

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