【问题标题】:Call function, if there is, ignore otherwise [duplicate]调用函数,如果有,否则忽略[重复]
【发布时间】:2013-02-24 11:45:27
【问题描述】:

我现在想做一个模板,它将一些元素推送到向量和其他类型,支持push_back 运算符。

我可以这样做

template<typename T>
T fill(size_t n) {
    T v;
    //(1)
    for(size_t i = 0; i < n; ++i){
        v.push_back(generate_some_how());
    }
    return v;
}

它有效。但现在我想使用v.reserve(n); 而不是(1) 来提高支持它的类型的速度。但我仍然希望能够为无法编译的类型编译此代码reserve

有什么简单的方法可以实现吗?

我知道我可能专注于硬编码类型,但它似乎并不好。

C++11 没问题。

【问题讨论】:

  • 我对此表示怀疑,但我不确定。我猜你将不得不使用模板专业化
  • 不太难......你需要编写一个特征来检测 reserve 成员函数的存在并具有正确的签名。使用该工具有不同的方法,您可以编写一个 reserve_ 模板函数,该函数使用该特征调度到对 reserve() 的调用或无操作并从 // (1) 调用它,或者您可以使用SFINAE 在帮助程序或fill 本身中。我会尝试使用辅助函数,因为fill 中的大部分代码都是相同的。
  • 如果您使用 C++11,请考虑支持适当的 emplace 调用以替换 push_back
  • 您是否有任何理由这样做,而不是仅仅在呼叫站点致电v.reserve(n); std::generate_n(std::back_inserter(v), n, generate_some_how);? (除了删除 1 行代码)或者它也可能更优化:v.resize(n); std::generate_n(v.begin(), n, generate_some_how);
  • 如果您期待标准容器或符合标准 container requirements 的容器,您应该选择 typename T::size_type 而不是 size_t

标签: c++ templates c++11


【解决方案1】:

一个使用 C++11 的简单示例:

template<class T>
auto maybe_reserve(T& v, size_t n, int)
    -> decltype(v.reserve(n), void())
{
  v.reserve(n);
}

template<class T>
void maybe_reserve(T&, size_t, long){}

template<typename T>
T fill(std::size_t n) {
    T v;
    maybe_reserve(v, n, 0);
    for(size_t i = 0; i < n; ++i){
        v.push_back(generate_some_how());
    }
    return v;
}

Live example.解释请看here

【讨论】:

  • C++03 版本也是可能的,尽管更加复杂和限制。
  • 在将resize 更改为reserve for deque ideone 后未编译
  • @RiaD:这是 GCC 4.7 的问题。 Clang 3.2 和 GCC 4.8 可以正常工作。可以通过将第一个重载的返回类型更改为 decltype(v.reserve(n), void()) 来解决 GCC 的错误。
  • 顺便说一句,也许你可以避免额外的虚拟参数?看到这个example :)
  • @Andy:可以,但是嗯,我想明确一点。 :)
【解决方案2】:

C++11 中一种可能的方法:

template<typename T, typename = void>
struct reserve_helper
{ static void call(T& obj, std::size_t s) { } };

template<typename T>
struct reserve_helper<T, decltype(std::declval<T>().reserve(0), void(0))>
{ static void call(T& obj, std::size_t s) { obj.reserve(s); } };

template<typename T>
T fill(std::size_t n)
{
    T v;
    reserve_helper<T>::call(v, 10);
    for(std::size_t i = 0; i < n; ++i){
        v.push_back(generate_somehow());
    }

    return v;
}

这是一个live example,显示对reserve() 的调用被一个未定义任何reserve() 成员函数的UDT 简单地跳过。

【讨论】:

  • 要求reserve 返回void(是的,通常情况下,我知道)。 :)
  • @Xeo: 好的,好的 :) 让我编辑
  • 你试过编译和运行这个吗? :3
  • @Xeo: I did :)
  • 太糟糕了doesn't work。 :3(提示:您正在“保留”10,但通话后的容量为4。)
【解决方案3】:

不太难......您需要编写一个特征来检测具有正确签名的保留成员函数的存在。使用该工具有不同的方法,您可以编写一个 reserve_ 模板函数,该函数使用该特征调度到对 reserve() 的调用或无操作并从 // (1) 调用它,或者您可以使用SFINAE 在帮助程序或fill 本身中。我会尝试使用辅助函数,因为填充的大部分代码都是相同的。

检测C++03中是否存在void reserve(std::size_t)成员函数:

template <typename T>
struct has_reserve {
   typedef char yes;
   typedef yes  no[2];
   template <typename U, U> struct ptrmbr_to_type;
   template <typename U> 
   static yes& test(ptrmbr_to_type<void (T::*)(std::size_t),&U::reserve>*);
   template <typename U> static no& test(...);
   static const bool value = sizeof(test<T>(0))==sizeof(yes);
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-06
    • 2015-07-11
    • 2021-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-17
    相关资源
    最近更新 更多