【问题标题】:When does `decltype` with a function call expression require the function to be defined?带有函数调用表达式的 `decltype` 何时需要定义函数?
【发布时间】:2014-03-27 19:28:52
【问题描述】:

在铿锵声中我收到了这个警告

warning: inline function 'detail::selector<2, int>::select' is not defined [-Wundefined-inline]
    static constexpr auto select(T const&) -> std::integral_constant<int, Which>;
                          ^

note: used here
static_assert( decltype(Selector::select(int()))::value == 2, "");
                                  ^

在下面的代码中。

这里不定义函数有害吗? (我坚信,在这里和我的应用程序中都没有关系,因为它在未评估的上下文中使用,在 std::enable_if 中)。

现在,我想知道什么时候编译器认为它应该发出警告。

#include <type_traits>

namespace detail {

    template <int Which, typename...> struct selector;

    template <int Which>
    struct selector<Which> {
        static constexpr void select();  // never select
    };

    template <int Which, typename T, typename... Ts>
    struct selector<Which, T, Ts...> : selector<Which+1, Ts...>
    {
        using selector<Which+1, Ts...>::select;
        static constexpr auto select(T const&) -> std::integral_constant<int, Which>;
    };
}

int main(int argc, const char * argv[])
{
    using Selector = detail::selector<0, char, short, int>;
    static_assert( decltype(Selector::select(int()))::value == 2, "");    
    return 0;
}

编辑:

注意事项:

  • ideone.com 上的 gcc-4.8.1 不会发出警告。

  • 摆脱警告的最简单方法是提供实现,例如:

    static constexpr auto select(T const&) 
    -> std::integral_constant<int, Which> 
    { return {}; }
    

    (感谢@Yakk)


解决方案

正如@Filip Roséen 提供的答案中所解释的,constexpr 说明符将隐式声明该函数内联,这需要在评估时定义。但是,该函数 not 在我的代码中使用 - 但仍然 clang 会发出该警告(表示编译器中的一个小问题)。当省略 constexpr 说明符时,clang 将不再发出此警告。无论如何,constexpr 说明符似乎不合适,(感谢@Yakk)。

【问题讨论】:

  • 有趣的是,它抱怨detail::selector&lt;2, int&gt;::select 不是函数的真实名称。 using selector&lt;Which+1, Ts...&gt;::select; 的实例化是对同一函数 constexpr void selector&lt;3&gt;::select(); 的重新声明,而不是不同的函数。
  • @aschepler 我不关注
  • @CouchDeveloper 为什么constexpr 没有实现?
  • @Yakk 这可能是多余的。我提取此演示 sn-p 的实际实现确实实现了它,例如:constexpr Result&lt;Which, T&gt; select(T const&amp;) { return Result&lt;Which, T&gt;(); }
  • @CouchDeveloper 为什么不return {}

标签: templates c++11 clang sfinae decltype


【解决方案1】:

注意;如前所述,clang 发出的诊断只是一个警告而不是错误,这意味着它只是为了吸引我们注意如果处理不当可能会被滥用的片段。


可能会出现什么问题?

标记为 constexpr 的实体隐含为inline(对于直接在类中定义的函数也是如此),如[dcl.fct.spec]p3 中所述。

具有inline 说明符的函数,无论是否隐含,都必须遵循应用于此类的规则。 clang 发出的警告是为了警告开发人员编写违反以下(以及其他)的代码:

[dcl.fct.spec]

4) 内联函数应在每个odr-used 的翻译单元中定义,并且在每种情况下都应具有完全相同的定义(3.2)。

[basic.def.odr]

2) 一个表达式可能被计算,除非它是一个未计算的操作数(第 5 条)...

3) 变量x 的名称显示为潜在评估 表达式exodr-used ...

4) ... 内联函数应在其odr-used的每个翻译单元中定义,并且在每种情况下都应具有完全相同的定义(3.2)。


clang 在我们的上下文中发出-Wundefined-inline 是否正确?

从技术上讲...,警告没有任何价值,因为我们在未评估的上下文中使用 select 并没有违反一个定义规则

您可以在调用 clang 时通过传递 -Wno-undefined-inline 来取消警告,如果这对您造成很大困扰,请 file a bug report

【讨论】:

  • 谢谢Filip,这个解释很清楚,现在我更彻底地理解了这个问题!也就是说,constexpr 隐式声明了函数inline,并且内联函数在使用 odr 时应具有定义。由于没有对函数求值,所以clang太挑剔了。我删除了上面代码中的constexpr 说明符,瞧,clang 不再发出此警告。 (用解决方案更新了我的问题)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-09
  • 1970-01-01
  • 2012-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多