编译器跳过 C++ 中的可变参数模板/函数 [关闭]
Posted
技术标签:
【中文标题】编译器跳过 C++ 中的可变参数模板/函数 [关闭]【英文标题】:Compiler skipping over variadic template/function in C++ [closed] 【发布时间】:2017-02-09 21:36:05 【问题描述】:免责声明 - 老实说,我不确定如何提出这个问题或提供适当的上下文,如果遇到此问题的人能推荐我需要提供哪些额外信息来澄清上下文,我将不胜感激。而且,如果我需要清理下面的代码部分以使其更清晰,我会在收到 cmets 时这样做!
但不管怎样-
我正在尝试使用可变参数模板,但每次我编译我的代码(它在公司代码库上)时,编译器(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 *o1TestFactory::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))
【问题讨论】:
c
-标签是有原因的,还是您只是觉得它美观?
模板仅在使用时进行实例化。将定义放在实现中而不使用它们在该文件中将导致没有实例化。然后,当您尝试在其他地方使用它时,它将找不到要实例化的实现,因为它位于当前翻译单元无法看到的实现文件中。您应该将实现留在标题中。 See this question.
@FrançoisAndrieux 我会试一试并提供更新!感谢您的链接!
@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;
为了清楚起见,我已经明确地编写了模板参数。在您的情况下,编译器将能够推导出这些参数,并且示例大大简化。您可以简单地调用不带任何参数的模板化方法,它们将从参数中推导出来。
// 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>
的符号。
【讨论】:
嘿,感谢您的详细回答,这样肯定有效!但令我难以置信的一件事是,我在任何目标文件中都找不到RegisterTest
或CreateTest
符号??!我检查了调用文件的.o
文件(在您的情况下为main.c
)以及TestFactory.o
?有什么想法吗?
@nitimalh 我不是 gcc 方面的专家,我无法自信地回答为什么你找不到符号。这可能是另一个问题的理由。以上是关于编译器跳过 C++ 中的可变参数模板/函数 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章