【问题标题】:Mechanism for extensible conditional statement可扩展条件语句的机制
【发布时间】:2015-01-29 15:28:35
【问题描述】:

我的代码中有这些行:

//lines in mycode.c++
  QString str = "...some id...";

       if( str == "int")
           foo< int>()
  else if( str == "QString")
           foo< QString>()
       ...

我需要创建一种机制以在此条件语句中包含自定义类型。因此,任何程序员都可以注册他的类和他的 foo 模板函数的实现。

我想是这样的:

//A.h -- custom class
class A { };

template< >
  void foo< A>() { ... };

DECL( A, "A"); //macro to declare class

我想要 mycode.c++ 中的条件语句,它会自动考虑类 A 的声明,所以它会有额外的行:

else if( str == "A")
    foo< A>()

我可以有这样的效果:

//common.h
  void process_id( QString str) {
       if( str == "int")
           foo< int>()
  else if( str == "QString")
           foo< QString>()
       ...
  else if( str == "A") //this lines programmer put manually
           foo< A>();
  }

//mycode.c++
  #include "common.h"

  QString str = "some_id";

  process_id( str);

但是如果程序员忘记编辑 common.h 文件怎么办?

我想,也许是使用 C 宏系统,或者不知何故 Qt 预编译。有可能吗?

【问题讨论】:

  • 当然可以。但是您需要注意,在某些时候,程序员必须提供可能的字符串列表及其结果,因此您仍然会遇到几乎相同的问题(尽管语法可能会更好一点)。
  • 您是否考虑过使用工厂/地图而不是 if/else 来调度呼叫?
  • 这感觉完全倒退了。既然可以使用 dispatch,为什么还要使用巨大的 if 块?
  • @MarkB 在我的 mycode.c++ 中,我需要使用由运行时变量决定的模板参数调用函数。如果我可以在没有 if/else 的情况下做到这一点 - 没关系。
  • @JohnDibling 调度?

标签: c++ qt compile-time qt4.8 pre-compilation


【解决方案1】:

我会这样做:

void process_id(QString const & str) 
{
   auto it =  g_actions.find(str);
   if ( it != g_actions.end() )  
         (it->second)(); //invoke action
}

而支持上述的框架实现为:

 using action_t = std::function<void()>;

 std::map<QString, action_t>  g_actions; //map of actions!

#define VAR_NAME(x)       _ ## x
#define DEFINE_VAR(x)  VAR_NAME(x)
#define REGISTER(type) char DEFINE_VAR(__LINE__) = (g_actions[#type] = &foo<type>,0)

现在您可以将任何类注册为:

 //these lines can be at namespace level as well!
 REGISTER(A);
 REGISTER(B);
 REGISTER(C);

然后调用process_id()为:

process_id("A"); //invoke foo<A>();
process_id("B"); //invoke foo<B>();

希望对您有所帮助。

this online demo

【讨论】:

  • 我认为 &foo 必须是 &foo。我应该将 g_actions 设为外部,还是像这样思考?
  • @ValentinT.:是的。这是正确的。编辑它,添加一个在线演示。
  • 谢谢,我知道这适用于 C++11。现在尝试为 4.9.2 (ideone.com/lG0sn1) 重新创建它。
  • 您需要使用DEFINE_VAR(__LINE__) 而不是char _ ##__LINE__
  • 另外typedef void action_t( void); 定义了一个函数类型,不是一个函数指针类型。使用typedef void (*action_t)(void);
【解决方案2】:

我只想创建一个函子向量:

using ProcessFunc = std::function<bool(const QString&)>;
std::vector<ProcessFunc> ids;

void process_id(QString str) {
    for (ProcessFunc& f : ids) {
        if (f(str)) {
            break;
        }
    }

    // or...
    std::any_of(ids.begin(), ids.end(), [&](const ProcessFunc& f){
        return f(str);
    });
}

您只需提供一种方法来附加新的ProcessFunc

template <typename T>
void register_class(const QString& name) {
    ids.emplace_back([=](const QString& str) {
        if (str == name) {
            foo<T>();
            return true;
        }
        else {
            return false;
        }
    });
}

您的示例具体是:

register_class<int>("int");
register_class<QString>("QString");
register_class<A>("A");

如果你真的想的话,我想你可以把它变成一个宏。

【讨论】:

  • ids 向量会是全局的吗?
  • @ValentinT。无论process_id 生活在哪里,都需要能够访问它。如果这是一个类,那么私有成员最有意义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-26
  • 2023-01-28
  • 2012-07-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多