如何处理void decltype();

时间:2015-05-19 02:12:13

标签: c++ templates c++11

我想创建一个模板,该模板在另一个返回与成员函数相同类型的对象上调用成员函数。在成员函数上使用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函数。我不介意创建另一个模板,但我想使用相同的名称&#34; safeOperation&#34;因此,呼叫站点不需要根据成员函数的返回类型使用不同的帮助程序。

谢谢!

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

2 个答案:

答案 0 :(得分:9)

不幸的是,我认为您在返回类型上不得不使用SFINAE。从类型特征开始(这是方式比您的private void txtBoxLogin_Click(object sender, EventArgs e) { try { OleDbConnection connection = new OleDbConnection(@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=S:\Docket\Database1.accdb; Persist Security Info=False;"); string cmdText = "select * from login where Username=" + "? and [Password]=?"; OleDbCommand cmd = new OleDbCommand(cmdText,connection); { connection.Open(); cmd.Parameters.AddWithValue("@p1", txtboxUsername.Text); cmd.Parameters.AddWithValue("@p2", txtBoxPassword.Text); int result = (int)cmd.ExecuteScalar(); if (result > 0) MessageBox.Show("Success"); else MessageBox.Show("Fail"); } connection.Close(); } catch (Exception ex) { MessageBox.Show("Error" + ex); } } 表达式更干净)

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...);
}

答案 1 :(得分:0)

这是一个极端的情况。 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)。