2017-02-09 66 views
0

免责声明 - 老实说,我不知道如何设置这个问题或提供适当的上下文,并希望如果有人遇到这个问题可以推荐什么额外的信息,我需要提供给澄清背景。而且,如果我需要清理下面的代码部分以使其更清晰,我会在收到评论时这样做!编译器在C++中跳过可变参数模板/函数

但无论如何,在这里去 -

我试图用可变参数模板工作,但每次我编译我的代码(其对公司的代码库)的编译器(gcc 4.8.4 - C++ 11)似乎跳过在所有的可变参数的代码段 -

TestFactory.cpp

/* 
* Use this design since Variadic Templates are not available in C++11 
* A MapHolder allows us to create a map of variadic functions. 
*/ 
template <class... Args> 
struct MapHolder 
{ 
    static std::map<std::string, NpBaseTest*(*)(Args...)> CallbackMap; 
}; 

template <class... Args> 
std::map<std::string, NpBaseTest *(*)(Args...)> MapHolder<Args...>::CallbackMap; 

class TestFactory 
{ 
public: 
    template <class... Args> 
    static void RegisterTest(std::string name, NpBaseTest *(*callback)(Args...)); 

    template <class... Args> 
    static NpBaseTest *CreateTest(const std::string &name, Args &&... args); 
}; 

TestFactory.cpp

template <class... Args> 
void TestFactory::RegisterTest(std::string name, NpBaseTest *(*callback)(Args...)) 
{ 
    MapHolder<Args...>::CallbackMap[name] = callback; 
} 

template <class... Args> 
NpBaseTest *TestFactory::CreateTest(const std::string &name, Args &&... args) 
{ 
    return (MapHolder<Args...>::CallbackMap[name])(std::forward<Args>(args)...); 
} 

调用文件 -

void np_test_mgr_print() 
    { 
     const char *s = "cavpkotest"; 
     std::string str(s); 
     TestFactory::RegisterTest(str.c_str(), &CavPkoTest::create); 
     NpBaseTest *o1{TestFactory::CreateTest<uint16_t>(str.c_str(), 1)}; 
     /* Irrelevant code section */ 
     NpTestMgr::get_instance().insert(o1); 
     NpTestMgr::get_instance().submit(); 
    } 
} 

当我编译这个(GCC 4.8.4)的目标文件TestFactory.o是空的。如果我这样做,我们的代码库外(GCC 4.4.6)的代码被编译和输出 -

[common]$ nm TestFactory.o | c++filt $1 | grep CreateTest 
34:0000000000401d6a W NpBaseTest* TestFactory::CreateTest<unsigned short>(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned short&&) 
[common]$ nm TestFactory.o | c++filt $1 | grep RegisterTest 
35:0000000000401d40 W void TestFactory::RegisterTest<unsigned short>(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, NpBaseTest* (*)(unsigned short)) 
+4

是否有'c'-tag的原因还是只是觉得它美观? – EOF

+1

模板仅在使用时实例化*。将该定义放在实现中而不使用*在该文件中*将导致不实例化。然后,当您尝试在其他地方使用它时,它将找不到要实例化的实现,因为它位于当前翻译单元无法看到的实现文件中。你应该在头文件中保留实现。 [看到这个问题](http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file)。 –

+0

@FrançoisAndrieux我会给你一个机会,并提供更新!感谢您的链接! – nitimalh

回答

1

模板仅在使用实例。将该定义放入实现中而不在该文件中使用它们将导致不实例化。然后,当您尝试在其他地方使用它时,它将找不到要实例化的实现,因为它位于当前翻译单元无法看到的实现文件中。你应该在头文件中保留实现。 See this question

你的例子工作正常,如果有一个NpBaseTest的定义,并且如果你移动头中的所有代码(我假设TestFactory.h)。这里是一个如何在你的例子中使用代码的例子。注意你的模板被写入的方式,它们只接受指向返回NpBaseTest*的函数的指针。

// main.cpp 
#include "TestFactory.h" 
#include <iostream> 

NpBaseTest* test_callback(int x, int y) 
{ 
    std::cout << "Called test_callback(" << x << ", " << y << ")\n"; 
    return nullptr; 
} 

int main() 
{ 
    // This instantiates TestFactory::RegisterTest<int, int> 
    TestFactory::RegisterTest<int, int>("my test", &test_callback); 

    // This instantiates TestFactory::CreateTest<int, int> 
    NpBaseTest * result = TestFactory::CreateTest<int, int>("my test", 5, 10); 

    return 0; 
} 

我已经为clariy写了明确的模板参数。在你的情况下,编译器将能够推导出这些参数,并且该示例被大大简化。你可以简单地调用模板化方法而不需要任何参数,它们将从参数中推导出来。

// main.cpp 
#include "TestFactory.h" 
#include <iostream> 

NpBaseTest* test_callback(int x, int y) 
{ 
    std::cout << "Called test_callback(" << x << ", " << y << ")\n"; 
    return nullptr; 
} 

int main() 
{ 
    // This instantiates TestFactory::RegisterTest<int, int> 
    TestFactory::RegisterTest("my test", &test_callback); 

    // This instantiates TestFactory::CreateTest<int, int> 
    NpBaseTest * result = TestFactory::CreateTest("my test", 5, 10); 

    return 0; 
} 

就是这样。如果尝试这个例子,你会看到现在生成TestFactory::RegisterTest<int, int>TestFactory::CreateTest<int, int>的符号。

+0

嘿谢谢你的详细答案,所以一定能工作!但有一点让我难以置信的是,我无法在任何目标文件中找到“RegisterTest”或“CreateTest”符号!我检查了调用文件的'.o'文件(在你的例子'main.c'中)和'TestFactory.o'?有任何想法吗 ? – nitimalh

+0

@nitimalh我不是gcc的专家,我无法以任何信心回答你为什么找不到符号。这可能是另一个问题的理由。 –

相关问题