在运行时确定主变量类型的函数

时间:2011-01-17 22:57:49

标签: c++ winapi

我有一个简单的问题我不知道如何解决,它来自使用python&习惯于处理数据类型无关紧要的变量。我正在使用Windows Task Scheduler&它拥有数以百万计的物品,ITask ...这个ITask ......那个。

所以我有一个功能,&根据参数triggerType(枚举变量),变量触发器将是ITimeTrigger或IBootTrigger类型...呃这在文本中很难解释,如果你看下面的代码就很容易看出我的问题是

通过查看下面的示例,我很容易理解我的问题:

enum meh { I_WANT_A_INT = 50001, I_WANT_A_FLOAT };

bool foo( meh triggerType )
{    
    switch ( triggerType )
    {
        case I_WANT_A_INT:
        {
             int trigger = 10;
        }
        break;
        case I_WANT_A_FLOAT:
        {
             float  trigger  = 10.111;
        }
        break;
        default:
        {
             double  trigger  = 11;
        }
        break;
    }

    trigger  = 5 * trigger ;   // Compile error because trigger is not declared
    cout <<  trigger  << endl;
}

我知道我可以使用的解决方案是:
- 我可以重载功能&amp;有一个用于ITimeTrigger(int)动作&amp;另一个是IBootTrigger(浮动)。这是我真的不想做的事情,因为函数非常长,而且它们之间有很多重复的代码 - ITimeTrigger&amp; IBootTrigger都从相同的对象ITrigger继承,所以我可以将交换机外部的触发器var声明为ITrigger,然后转换为交换机中我需要的对象。这将现在起作用,但是当我 扩展此函数以安排不同类型的任务触发器不会从ITrigger继承(win32语义再次),因此该解决方案无法工作。

如何声明变量触发器(其数据类型将在运行时确定),以便稍后我可以在函数中使用var?

4 个答案:

答案 0 :(得分:7)

您可以使用模板来避免代码重复。例如,以上内容可以改写为:

// Common code goes here:
template<typename TriggerType>
void bar(TriggerType trigger)
{
    trigger *= 5;
    std::cout << trigger << std::endl;
}

// Differing code goes here:
void foo(meh trigger_type)
{
    switch (trigger_type) {
    case I_WANT_A_INT:
        bar(10); // invokes the int version
        break;
    case I_WANT_A_FLOAT:
        bar(10.111f); // invokes the float version; note the use of 'f'
        break;
    default:
        bar(11.0); // invokes the double version; note the use of '.0' and lack of 'f'
    }
}

对于行为完全不同的类型,您还可以拥有bar的专门实例。

答案 1 :(得分:0)

这在C ++中没有用;类型是在运行时确定的。虽然你可以创建一个类似于内置类型的类的层次结构,为它们多态地重载operator*等,但我会质疑为什么你想要混合像这样的原始类型?

如果您想为不同类型使用不同版本的函数,但没有代码重复,那么您可能希望查看使用函数模板。参见例如http://www.parashift.com/c++-faq-lite/templates.html

答案 2 :(得分:0)

#include <iostream>
using namespace std;

enum meh { i_want_a_int = 50001, i_want_a_float };

template< class Number >
bool bar( Number trigger )
{
    trigger  *= 5;
    cout <<  trigger  << endl;
    return true;
}

bool foo( meh triggerType )
{    
    switch ( triggerType )
    {
        case i_want_a_int:
            return bar<int>( 10 );
        case i_want_a_float:
             return bar<float>( 10.111f );
        default:
             return bar<double>( 11.0 );
    }
}

int main()
{
    foo( i_want_a_float );
}

顺便说一下,通过为宏保留ALL_UPPERCASE个标识符,可以大大减少无意中文本替换的可能性。

干杯&amp; HTH,

答案 3 :(得分:0)

模板是可能的解决方案。

它不得不说没有看到更多的细节,但我注意到你说“这个函数真的很长,有很多重复的代码”。

你可以:

  1. 单一功能模板
  2. 将重构转换为类模板, 使用非类型特定代码 基类方法可能运行良好
  3. 一些功能的集合 这是模仿的 顶级函数被模板化
  4. 顶级模板化功能 超载的一些 子例程。
  5. 请注意,您还可以使用模板从枚举映射到类型:

    enum meh { I_WANT_A_INT = 50001, I_WANT_A_FLOAT, I_WANT_A_DOUBLE };
    
    template<meh = I_WANT_A_DOUBLE>
    struct TriggerType
    {
        typedef double Type;
    };
    template<>
    struct TriggerType<I_WANT_A_INT>
    {
        typedef int Type;
    };
    template<>
    struct TriggerType<I_WANT_A_FLOAT>
    {
        typedef float Type;
    };
    
    template<class T> void setValue(T& t);
    
    template<> void setValue<double>(double& t) { t = 11;}
    template<> void setValue<int>(int& t) { t = 10;}
    template<> void setValue<float>(float& t) { t = 10.111f;}
    
    template<class T> 
    bool fooTyped()
    {
        T trigger;
        setValue(trigger);
        trigger *= 5;
        std::cout <<  trigger  << std::endl; 
        return true;
    }
    
    bool foo( meh triggerType )
    {    
        bool ret = false;
        switch ( triggerType )
        {
            case I_WANT_A_INT:
            {
                ret = fooTyped<TriggerType<I_WANT_A_INT>::Type>(); ;
            }
            break;
            case I_WANT_A_FLOAT:
            {
                ret = fooTyped<TriggerType<I_WANT_A_FLOAT>::Type>(); ;
            }
            break;
            default:
            {
               ret = fooTyped<TriggerType<I_WANT_A_DOUBLE>::Type>(); ;
            }
            break;
        }
        return ret;
    }    
    
    void test ()
    {
        foo(I_WANT_A_INT);
        foo(I_WANT_A_FLOAT);
        foo((meh)63);
    }
    

    注意枚举映射到类型的调度;我们需要这个显式的样板,因为我们不能使用运行时值来实例化模板。