如果包为空,是否对可变参数包类型执行替换?

2022-01-23 00:00:00 g++ clang c++ c++11 sfinae

考虑以下程序:

#include <type_traits>

enum class dummy {};
template <typename T>
using EnableIf = typename std::enable_if<T::value, dummy>::type;
template <typename T>
using DisableIf = typename std::enable_if<!T::value, dummy>::type;

template <typename T>
struct dependent_true_type : std::true_type {};

template <typename T,
          EnableIf<dependent_true_type<T>>...>
std::true_type f();
template <typename T,
          DisableIf<dependent_true_type<T>>...>
std::false_type f();

static_assert(decltype(f<int>())::value, "");

int main() {}

GCC 4.7 高兴接受这个程序.我最近的 clang 3.1 版本声称对 f 的调用不明确.

GCC 4.7 glady accepts this program. My recent clang 3.1 build claims the call to f is ambiguous.

test.c++:22:24: fatal error: call to 'f' is ambiguous
static_assert(decltype(f<int>())::value, "");
                       ^~~~~~
test.c++:17:16: note: candidate function [with T = int, $1 = <>]
std::true_type f();
               ^
test.c++:20:17: note: candidate function [with T = int, $1 = <>]
std::false_type f();
                ^
1 error generated.

如果我写 f<int, dummy{}>(),它确实接受程序.

It does accept the program if I write f<int, dummy{}>().

当包为空时,clang似乎没有考虑参数包的类型,这导致没有将其从候选集中删除.即使包为空,GCC 似乎也会对参数包类型执行替换,并且由于所述替换因一次重载而失败,因此没有歧义.

It seems clang does not consider the type of the parameter pack when the pack is empty, which leads to not removing it from the candidate set. GCC seems to perform substitution on the parameter pack type even if the pack is empty, and since said substitution fails for one overload, there is no ambiguity.

这两个哪个是正确的?

推荐答案

我相信我已经找到了相关的标准.§14.8.2p7 说:

I believe I have found the relevant piece of standardese. §14.8.2p7 says:

替换发生在函数类型和模板参数声明中使用的所有类型和表达式中.

The substitution occurs in all types and expressions that are used in the function type and in template parameter declarations.

由于在模板参数声明中使用了 EnableIf<dependent_true_type<T>>,因此应该进行替换,这是 clang 中的一个错误.

Since EnableIf<dependent_true_type<T>> is used in a template parameter declaration, substitution should occur and this is a bug in clang.

相关文章