#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;
template <typename T>struct trait<T, std::void_t<decltype(std::declval<T>().begin())>>
{
static const char* name() { return "Container"; }
};
template <typename T>struct trait<std::vector<T>,void> {
static const char* name() { return "std::vector"; }
};
我不打算解释如何进行部分排序,这将太长时间。在转换为函数等之后,您最终会得到类似于以下内容的东西。
现在我们需要展示#2中的#1是否起作用。如果确实如此,我们已经表明#2更加专业化。
这基本上是我的草图,没有检查标准或其他任何东西。我相信你可以在标准的无尽行中找到它...
如果您注意到了(*),那么这一行基本上是唯一重要的,如果您想使用decltype(...)。我的猜测是,使用decltype(...)导致右侧的非推断上下文,这可能不允许使用P1 / A1推断中的T。但是,这基本上是我第一次没有包含答案的工作std::void_t解决方案的原因。
最后,替代的std::void_t
定义与typename ...也是我认为像decltype(...)一样的非推断上下文,由于typename部分。
编辑
只是添加一些最终行。原则上,decltype sfinae不应该有问题。好吧,它是非推断上下文,但为什么会有问题?我能想到的唯一一件事是,非推断上下文在部分排序组合中具有一些特殊规则...