草庐IT

c++ - dynamic_cast<> 将变量参数传递给模板

coder 2024-02-14 原文

我有一个执行测试用例的 C++ 应用程序。某些测试用例可能会依赖于其他测试用例的输出。

所有测试用例都实现一个基本接口(interface):

/// base class for all test cases
class ITest
{
public:
    virtual void Execute() = 0;
};

产生一些可能对其他测试用例有用的对象的测试用例实现这个接口(interface):

/// implemented by test cases that provide data to other test cases
template< class Obj >
class IDependency
{
public:
    virtual Obj Get() = 0;
};

需要来自其他测试用例的数据的测试用例实现此接口(interface):

/// implemented by test cases that require data from other test cases
template< class Obj >
class IDependent
{
public:

    void SetDependency( IDependency< Obj >* dependency )
    {
        dependency_ = dependency;
    };

protected:
    Obj GetDependency() const
    {
        return dependency_->Get();
    };

private:
    IDependency< Obj >* dependency_;
};

两个示例测试用例。一个需要一个 const wchar_t 对象;一个产生那个对象:

/// A test case that provides a "const wchar_t*" object to other test cases
class Foo : public ITest, 
            public IDependency< const wchar_t* >
{
public:
    const wchar_t* Get() 
    { 
        if( object_.length() == 0 )
            Execute();
        return object_.c_str();
    };

    virtual void Execute()
    {
        printf( "Execute Foo\n" );
        object_ = L"Object produced by Foo";
    };

private:
    std::wstring object_;
};

/// A test case that first requires a "const wchar_t*" object
class Bar : public ITest,
            public IDependent< const wchar_t* >
{
public:

    virtual void Execute()
    {
        const wchar_t* needed_object = GetDependency();

        printf( "Execute Bar with %S\n", needed_object );
    };
};

测试用例存储在列表中。案例通过注册过程添加到列表中:

/// List of test cases to execute
std::vector< ITest* > list_;

/// Register a test case to execute with the system
void Register( ITest* test_case )
{
    list_.push_back( test_case );
}

这是我的问题。我想实现也接受依赖项的“Register()”函数的重载。但是,因为依赖项可以是任何类型(不仅仅是本示例中的“const wchar_t*”),所以我不确定如何管理它。下面是我正在寻找的或多或少的示例,但我不确定如何让它工作。

/// Register a test case with dependencies with the system
void Register( ITest* test_case, ITest* dependency, ... )
{
    IDependent< ??? >* dependent = dynamic_cast< IDependent< ??? >* >( test_case );
    IDependency< ??? >* dep = dynamic_cast< IDependency< ??? >* >( dependency );

    va_list dep_list;
    for( va_start( dep_list, dependency ); 
         NULL != dep; 
         dep = dynamic_cast< IDependency< ??? >* >( va_arg( dep_list, ITest* ) ) )
    {
        dependent->SetDependency( dep );
    }
    va_end( dep_list );

    Register( test_case );
}

用法示例:

int _tmain( int argc, _TCHAR* argv[] )
{
    /// Test case Foo
    Foo foo;

    /// Test case bar (depends on Foo)
    Bar bar;

    /// Register test case Bar with a dependency on Foo
    Register( &bar, &foo );

    /// Execute Bar. Because it depends on Foo, that will be executed first
    list_->begin()->Execute();
    return 0;
}

预期输出:

Execute Foo
Execute Bar with Object produced by Foo

有人对我如何成功实现此架构有任何建议吗? (或者实际有效的更好架构?)

谢谢, 保罗H

最佳答案

我看到了两种可能的解决方案。

静态

使 Register() 方法成为模板。 简单的解决方案是将依赖项的数量限制在某个合理的最大值。

template <class T, class D1>
void Register(T* test_case, IDependency<D1>* d1)
{
    BOOST_STATIC_ASSERT(boost::is_base_and_derived<IDependent<D1>, T>::value);
    // since we now know that T is a IDependent<D1>, a dynamic_cast would only be necessary
    // to allow virtual inheritance.
    static_cast<IDependent<D1>*>(test_case)->SetDependency(d1);
    Register(test_case);
}

template <class T, class D1, class D2>
void Register(T* test_case, IDependency<D1>* d1, IDependency<D2>* d2)
{
    BOOST_STATIC_ASSERT(boost::is_base_and_derived<IDependent<D1>, T>::value);
    static_cast<IDependent<D1>*>(test_case)->SetDependency(d1);
    Register(test_case, d2);
}

template <class T, class D1, class D2, class D3>
void Register(T* test_case, IDependency<D1>* d1, IDependency<D2>* d2, IDependency<D3>* d3)
{
    BOOST_STATIC_ASSERT(boost::is_base_and_derived<IDependent<D1>, T>::value);
    static_cast<IDependent<D1>*>(test_case)->SetDependency(d1);
    Register(test_case, d2, d3);
}

// ...

对于支持可变参数模板的编译器,这可能只用一个函数模板编写,以获得无限数量的依赖项。

或者你可以让 Register() 返回一个代理类,这样你就可以这样写:

Register(test_case)(dep1)(dep2)(dep3) /* ... */ (depN);

代理类将存储指向容器和测试用例的指针,并定义一个函数调用运算符,它看起来就像上面示例中的 Register(T* test_case, IDependency* d1) 函数,只是没有“test_case”参数和对 Register(test_case) 的最终调用(可以在代理类的 dtor 中执行)。

动态

如果我理解您正在尝试正确执行的操作,则每个“依赖项”只能产生一种类型的结果。 在这种情况下,您可以像这样修改 IDependency 接口(interface):

class IDependencyBase
{
public:
    virtual void ApplyTo(ITest* target) = 0;
};

template <class T>
class IDependency : public IDependencyBase
{
public:
    virtual void ApplyTo(ITest* target)
    {
        // cast to reference gives us an std::bad_cast if the types are not compatible,
        // which I think is a good thing here
        dynamic_cast<IDependancy<T>&>(*target).SetDependancy(this); 
    }

    virtual T Get() = 0;
};

template <class InputIterator>
void Register(ITest* test_case, InputIterator begin, InputIterator end)
{
    for (; begin != end; ++begin)
    {
        IDependancyBase* dep = *begin;
        dep->ApplyTo(test_case);
    }
    Register(test_case);
}

template <class Container>
void Register(ITest* test_case, Container deps)
{
    Register(test_case, deps.begin(), deps.end());
}

现在您似乎很想再次实现您的可变参数解决方案,就像这样(从第二个示例继续):

void Register(ITest* test_case, ...)
{
    va_list dep_list;
    va_start(dep_list, test_case);
    while(IDependencyBase* dep = va_arg(dep_list, ITest*))
        dep->ApplyTo(test_case);

    va_end(dep_list);

    Register( test_case );
}

// and use it like

int _tmain( int argc, _TCHAR* argv[] )
{
    Foo foo;
    Bar bar;

    Register(&foo);
    Register(&bar, &foo, 0);

    list_->begin()->Execute();
    return 0;
}

然而,这并不能保证有效。在上面的代码中,一个 Foo* 被存储为一个 varagrs 参数,并作为一个 IDependencyBase* 读回。这不能保证有效,因为 Foo 和 IDependencyBase 都不是 POD(IIRC 它们都必须是 POD 才能保证有效——也许即使那样也不能保证,我必须在标准中查找它) .这不是什么牵强附会的“不受标准保证但可以在任何地方工作”的事情。引入多重和/或虚拟继承,这几乎肯定会失败。

所以使用 C++ 时的一般建议:除非没有其他方法,否则不要使用可变参数函数。而且总有另一种方式。

关于c++ - dynamic_cast<> 将变量参数传递给模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3764912/

有关c++ - dynamic_cast<> 将变量参数传递给模板的更多相关文章

  1. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  2. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  3. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  4. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  5. ruby-on-rails - rspec should have_select ('cars' , :options => ['volvo' , 'saab' ] 不工作 - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request

  6. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  7. ruby-on-rails - Nokogiri:使用 XPath 搜索 <div> - 2

    我使用Nokogiri(Rubygem)css搜索寻找某些在我的html里面。看起来Nokogiri的css搜索不喜欢正则表达式。我想切换到Nokogiri的xpath搜索,因为这似乎支持搜索字符串中的正则表达式。如何在xpath搜索中实现下面提到的(伪)css搜索?require'rubygems'require'nokogiri'value=Nokogiri::HTML.parse(ABBlaCD3"HTML_END#my_blockisgivenmy_bl="1"#my_eqcorrespondstothisregexmy_eq="\/[0-9]+\/"#FIXMEThefoll

  8. ruby - rails 3 redirect_to 将参数传递给命名路由 - 2

    我没有找到太多关于如何执行此操作的信息,尽管有很多关于如何使用像这样的redirect_to将参数传递给重定向的建议:action=>'something',:controller=>'something'在我的应用程序中,我在路由文件中有以下内容match'profile'=>'User#show'我的表演Action是这样的defshow@user=User.find(params[:user])@title=@user.first_nameend重定向发生在同一个用户Controller中,就像这样defregister@title="Registration"@user=Use

  9. ruby-on-rails - 如何生成传递一些自定义参数的 `link_to` URL? - 2

    我正在使用RubyonRails3.0.9,我想生成一个传递一些自定义参数的link_toURL。也就是说,有一个articles_path(www.my_web_site_name.com/articles)我想生成如下内容:link_to'Samplelinktitle',...#HereIshouldimplementthecode#=>'http://www.my_web_site_name.com/articles?param1=value1¶m2=value2&...我如何编写link_to语句“alàRubyonRailsWay”以实现该目的?如果我想通过传递一些

  10. ruby-on-rails - 使用 ruby​​ 将多个实例变量转换为散列的更好方法? - 2

    我收到格式为的回复#我需要将其转换为哈希值(针对活跃商家)。目前我正在遍历变量并执行此操作:response.instance_variables.eachdo|r|my_hash.merge!(r.to_s.delete("@").intern=>response.instance_eval(r.to_s.delete("@")))end这有效,它将生成{:first="charlie",:last=>"kelly"},但它似乎有点hacky和不稳定。有更好的方法吗?编辑:我刚刚意识到我可以使用instance_variable_get作为该等式的第二部分,但这仍然是主要问题。

随机推荐