在decltype中使用命名空间

3

我有一个函数看起来差不多是这样的:

template<class C> auto f(C const& c) -> decltype(begin(c)){
    using std::begin;
    return begin(c);
}
  1. 该函数的主体利用了“using和use”习惯用法,并且

  2. 由于使用了decltype,如果返回类型无效,则会进行SFINAE。

然而,通常情况下并不完美,因为我无法告诉decltypebegin上使用using std声明。

template<class C> auto f(C const& c) -> decltype(std::begin(c))

这也可能是不一致的,例如当decltype(c)begin属于不同的命名空间时。

有什么解决方法吗?

理想情况下,我希望有像这样的东西:

template<class C> auto f(C const& c) -> decltype(using std::begin; begin(c))

我认为原则上lambda函数可以发挥作用。
template<class C> auto f(C const& c) -> decltype([&]{using std::begin; return begin(c)})

但是在decltype内部禁止使用lambda表达式。


在GCC中,有一种有趣的语言扩展(“表达式语句”),它很有前途,但它不能在函数体外部工作(与lambda表达式不允许在未求值上下文中相同)。否则,它将是一种解决方案。

template<class C> auto g(C const& c) 
->decltype(({using std::begin; begin(c);})){ // ...that doesn't work here
    return(({using std::begin; begin(c);})); // gcc extesion...
}
1个回答

5
你可以委托给一个启用了ADL的命名空间。
namespace detail
{
    using std::begin;
    template<class C> auto f(C const& c) -> decltype(begin(c)){
        return begin(c);
    }
}

template<class C> auto f(C const& c) -> decltype(detail::f(c)){
    return detail::f(c);
}

2
或者只需使用 detail::f - n. m.
@alfC 嗯,其实差不多的代码量,你可能会将你的 maybe_std_begin 放在 detail 或类似的私有命名空间中。所以你只是省略了尾随返回类型。这导致你的版本具有 auto 的返回类型推断,而我的版本具有 decltype 的行为,虽然对于像 begin 这样的东西应该没有关系,但如果 f 调用了其他函数,则可能存在影响。 - Praetorian
@alfC 是的,现在你的版本应该表现得一样了。无论如何,如果你更喜欢那个版本,你应该接受自己的答案。 - Praetorian
测试SFINAE友好性 https://wandbox.org/permlink/HqmmQupcQIN3N4ok - alfC
@alfC 你能分享一下这个问题的C++14解决方案吗? - orLcount
1
@orLcount,很抱歉让你失望了,我当时以为找到了解决方案,但实际上是垃圾。所以我删除了在这个帖子中的回答。我将删除我的评论。这里是这些(我认为是不正确的)答案的视图。https://pasteboard.co/K6sS3oGp.png - alfC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接