c++ - SFINAE,演绎与实例化

标签 c++ standards

此代码无法在大多数编译器中编译,但起初我直觉地希望 SFINAE 能保护我:

typedef void (*A)();

template < typename T >
struct a_metafun { typedef typename T::type type; };

template < typename T >
typename a_metafun<T>::type f(T) {}

template < typename T>
void f(T(*)()) {}

int main() { f(A()); }

我至少可以通过两种方式解决问题:

  1. 将“metafun”f() 的定义更改为:

    template < typename T > typename T::type f(T) {}

  2. 定义a_metafun这样它就可以分析 T并且有一个类型 if T有一个,如果没有,则没有……但是无论哪种方式都可以无错误地实例化:

    BOOST_MPL_HAS_XXX_TRAIT_DEF(type)
    
    typedef < template T, bool = has_type<T>::value >
    struct a_metafun { };
    
    typedef < template T >
    struct a_metafun<T, true> { typedef typename T::type type };
    

在查看 14.8.2 (C++03) 时,在我看来它明确指定了 SFINAE 可以应用的条件。有没有更好的地方看?已推导模板的实例化失败,即使是在推导另一个模板的过程中,似乎也不会包含在此列表中。

我解释是什么导致此非法的另一个方向是 a_metafun 的推导已经发生,其内部实例化是导致错误的原因。 SFINAE 在实例化期间不适用,但仅在推导期间适用,或者我错了吗?但在第二种情况下,a_metafun 被正确且格式良好地实例化,但它内部根本没有“类型”定义,这意味着尝试实例化它的模板由于替换而失败。

基本上我想知道标准中的哪些内容指定了我正在目睹的行为。我试过的每个编译器都会提示,甚至是 comeau。我认为他们这样做是正确的,我只是不完全确定为什么。

那么,专家们……什么是什么?为什么类型的实例化,即使在 f() 中的推导上下文中也会导致错误而不是 SFINAE 排除?

最佳答案

在 C++03 规范中,SFINAE 的规则有点模糊,允许编译器作者去任何长度来找到导致 SFINAE 的替换失败。 C++03 的相关文本 §14.8.2/2 说,

- [...] If a substitution in a template parameter or in the function type of the function template results in an invalid type, type deduction fails [...]

它进一步解释了失败的几个原因,但没有一个真正说明在什么时候替换失败应该被视为 SFINAE。所以我想,您的代码可能在 C++03 中运行良好(也可能无法正常运行,具体取决于编译器作者如何解释文本。无论如何,这让我感到困惑)。

但 C++11 中的措辞已得到改进,消除了模糊性。它在 §14.8.2/8 中说,

If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed if written using the substituted arguments. [ Note: Access checking is done as part of the substitution process. —end note ] Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure.

术语“直接上下文” 很有趣,我认为它适用于您的情况。更具体地说,元函数 a_metafun 中的替换失败不被视为函数类型的“直接上下文”。它在 C++11 中是病式的,在 SFINAE 中不是。

但是,尽管 C++11 引入了短语“直接上下文”以使文本稍微好一点,但该短语的定义仍然不够明确。这是一个活跃的问题:

关于c++ - SFINAE,演绎与实例化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14098131/

相关文章:

c++ - 得到 std::bind 的结果类型

c++ - std::bitset<0> 的大小?

xml - HTML 是否应该尽可能像 XML 一样格式化?

c++ - "class template"与 "template class"

c - extern 关键字对 C 函数的影响

C++ 动态内存分配 - char*

c++ - 在 OpenCV 中移动图像内容

c# - C++ 在 C# 中有类似 List<string> 的东西吗?

standards - 什么时候最好更改代码以符合标准?

c - `printf("%.-1s\n", "foo")` 会调用未定义的行为吗?