【问题标题】:How to handle void decltype();如何处理 void decltype();
【发布时间】:2015-05-19 02:12:13
【问题描述】:

我想创建一个模板,该模板调用另一个对象的成员函数,该对象返回与成员函数相同的类型。在成员函数上使用 decltype 的语法有点难看,但它似乎在除一种情况外的所有情况下都有效。

来电:

struct container: map<string, C> 
{
    template< typename MemFnPtrType, typename... _ArgTypes>
    auto safeOperation(string key, MemFnPtrType mfp, _ArgTypes&&... args )
        -> decltype( (((C*)nullptr)->*mfp)(args...))
    {
        C* pC = NULL;
        decltype((pC->*mfp)(args...)) result;

        iterator it = find(key);
        if (it != end())
        {
            C* pC = &(it->second);
            result = (pC->*mfp)(args...);
            cout << "result:" << result << "\n";
        }
        else
        {
            cout << "key: " << key << " missing\n";
        }
        return result;
    }
};

在成员函数返回 void 之前,这可以正常工作。

有没有办法检测到这一点并忽略违规行?

我显然可以创建一个 voidSafeOperation 函数。我不介意创建另一个模板,但我想使用相同的名称“safeOperation”,这样调用站点就不需要根据成员函数的返回类型使用不同的帮助器。

谢谢!

完整示例: http://cpp.sh/7ft

【问题讨论】:

    标签: c++ templates c++11


    【解决方案1】:

    不幸的是,我认为您不得不在返回类型上使用 SFINAE。从类型特征开始(这方式比你的 decltype 表达式更干净)

    template <typename MF, typename... Args>
    using Res = typename std::result_of<MF(C, Args...)>::type;
    

    然后切换:

    template <typename MF, typename... Args>
    typename std::enable_if<
        std::is_same<Res<MF, Args...>, void>::value
    >::type safeOperation(string key, MF mfp, Args... args)
    {
         /* void case */
    }
    
    template <typename MF, typename... Args>
    typename std::enable_if<
        !std::is_same<Res<MF, Args...>, void>::value,
        Res<MF, Args...>
    >::type safeOperation(string key, MF mfp, Args... args)
    {
         /* non-void case */
    }
    

    或者您可以在is_void 上标记调度:

    template <typename MF, typename... Args>
    Res<MF, Args...> safeOperation(string key, MF mfp, Args... args)
    {
        return safeOperation(std::is_void<Res<MF, Args...>>{},
                             key, mfp, args...);
    }
    

    与:

    template <typename MF, typename... Args>
    void safeOperation(std::true_type /* void */, 
                       string key, MF mfp, Args... args) 
    { .. }
    
    template <typename MF, typename... Args>
    Res<MF, Args...> safeOperation(std::false_type /* non-void */, 
                                   string key, MF mfp, Args... args) 
    { .. }
    

    【讨论】:

    • 或在is_void上标记调度。
    • @T.C.我通常不是一个超级粉丝,但在这种情况下它非常干净。
    • 我能够编译第一个案例,但使用 is_void 调度的 !void 案例中结果的语法似乎让我无法理解:cpp.sh/7mep
    • @BitBlitz 哎呀!固定。
    • 完美,谢谢!以后来的人的工作示例:cpp.sh/6aav 当我尝试将其放入我的构建环境时,GCC (4.6) 太旧了,但支持丑陋的 decltype() - 我仍然能够解决 void 问题is_void 标签。不漂亮,但为我节省了大量工作。再次感谢!
    【解决方案2】:

    这是一个角落案例。 autodecltype 用于尾随返回类型不适用于 void 返回类型,因为 void 是不完整的类型。

    示例:

    auto nothingMuch()
    {
        return;
    }
    
    // nope
    //decltype(void {}) nothingMuchEither()
    //{
    //  return;
    //}
    
    // nope
    //auto noTrailing() -> decltype(void {})
    //{
    //
    //}
    
    // always works
    decltype(auto) nothing()
    {
        return;
    }
    
    auto main() -> decltype(int {})
    {
        nothing();
        nothingMuch();
        return 0;
    }
    

    最简单的解决方法是将尾随返回类型中的autodecltype 替换为decltype(auto) 作为返回类型(需要C++14)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-22
      • 2017-01-09
      • 2020-10-09
      • 2013-10-21
      • 2012-12-09
      • 1970-01-01
      相关资源
      最近更新 更多