C++中一个模板函数中使用的类的不常见函数

uncommon function of classes used in one template function in C++

本文关键字:函数 不常见 一个 C++      更新时间:2023-10-16

>我将在以下代码中传递"堆栈"和"队列"作为模板类型。

知道 .front() 和 .top() 不是"queue"和"stack"之间的通用函数,我使用 "if" 进行检查。

但它仍然无法编译。(错误 C2039:"top"不是 std::queue<_Ty> 的成员)

有没有办法解决这个问题?

template<typename T>
void push_pop(string *str, T *containers){
    string s = typeid(containers).name();
    if(s[11]=='q'){
        str->push_back(containers->front()); containers->pop();
    }else{
        str->push_back(containers->top()); containers->pop();
    }
}

我知道我可以使用函数重载,但我想使用模板解决这个问题。

感谢您的回答!

问题是编译器必须编译检查的两个分支,并且它不能为队列编译container.top(),也不能为堆栈编译container.front()

您必须为std::queuestd::stack实现单独的函数模板:

template<typename V, typename C>
void push_pop(std::string &str, std::stack<V, C> &container) {
  str.push_back(container.top());
  container.pop();
}
template<typename V, typename C>
void push_pop(std::string &str, std::queue<V, C> &container) {
  str.push_back(container.front());
  container.pop();
}

可以(我建议这样做)仅对相关部分执行此操作:

template<typename V, typename C>
V const &first_element(std::stack<V, C> const &container) {
  return container.top();
}
template<typename V, typename C>
V const &first_element(std::queue<V, C> const &container) {
  return container.front();
}
template<typename T>
void push_pop(std::string &str, T &container) {
  str.push_back(first_element(container));
  container.pop();
}

(未经测试) - 我使用如下所示的宏:

#define FUNC_TEST(func)                                                     
template<typename T>                                                        
struct has_##func                                                           
{                                                                           
  template <typename _1> static std::true_type  test(decltype(&_1::func)*); 
  template <typename   > static std::false_type test(...);                  
  static const bool value =  decltype(test<T>(0))::value;                   
}

然后,对于我需要测试的所有函数,我将使用宏来生成测试代码,例如:

FUNC_TEST(top);
FUNC_TEST(front);

然后,我将定义几个帮助程序函数来处理实际的回推:

// If the type supports top(), then the first variant is enabled and selected
template <typename F>
inline enable_fn<has_top<F>, void> use_top(F* o, std::string* dest)
{ dest->push_back(o->top()); }
template <typename F>
inline disable_fn<has_top<F>, void> use_top(F*, std::string*)
{ }
// If the type supports front(), the first variant is selected from below automatically
template <typename F>
inline enable_fn<has_front<F>> use_front(F* o, std::string* dest)
{ dest->push_back(o->front()); }
template <typename F>
inline disable_fn<has_front<F>> use_front(F*, std::string*)
{ }
调用

时,只需调用两个变体,编译器将根据 SFINAE 测试选择适当的操作。

template<typename T>
void push_pop(string *str, T *container){
  use_top(container, str);
  use_front(container, str);
  container->pop();
}

看起来我们正在调用top()front(),但根据容器是否支持top()front()将编译出一个或另一个函数调用。如果类型 T 同时支持 front()top() ,这有点问题,但我会把它留给你一个练习来修复......

(注意:您需要enable_fn看起来像:

template <typename T>
using type_of = typename T::type;
template <typename C, typename R = void>
using enable_fn = type_of<std::enable_if<C::value, R>>;

我会把disable_fn留给你做练习...

代码的问题在于您正在尝试进行运行时检查,这导致容器类同时提供 top() 和 front() 的要求。正如@Wintermute所建议的那样,解决此问题的一种方法是使用模板专用化。如果你想要更花哨和通用的方式,你可以使用 SFINAE 方法,它与 C++11 相结合,提供干净漂亮的代码。假设我们只有两种可能的容器 - 提供 front() 或 top() 方法(添加新类型的函数非常容易):

template<typename container>
auto get_from_container(container* c, int) -> decltype(std::declval<container>().front(), typename container::value_type()) {
    return c->front();
}
template<typename container>                       
typename container::value_type get_from_container(container* c, long) {
    return c->top();
}
template<typename T>
void push_pop(string *str, T *containers){
    str->push_back(get_from_container(containers, 0)); containers->pop();
}

请注意 get_from_container 中的第二个类型参数 - 需要使用 top() 方法隐藏"默认"实现(如此处所述)