c++ - 编译器跳过 C++ 中的可变参数模板/函数

标签 c++ c++11 gcc compilation

<分区>

免责声明 - 老实说,我不确定如何提出这个问题或提供适当的上下文,如果遇到此问题的人可以推荐我需要提供哪些额外信息来澄清上下文,我将不胜感激。而且如果我需要清理下面的代码部分以使其更清晰,我会在收到评论时这样做!

但不管怎么说 -

我正在尝试使用可变参数模板,但每次我编译我的代码(它在公司代码库上)时,编译器(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))

最佳答案

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

如果有 NpBaseTest 的定义,您的示例可以正常工作并且如果您移动 header 中的所有代码(我假设是 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>现在生成。

关于c++ - 编译器跳过 C++ 中的可变参数模板/函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42147335/

相关文章:

c++ - 删除字符串流中的最后一个字符?

python - 在多线程中调用 Py_Initialize()

C: 将 "static const char * const"分配给 "static const char *"

头文件的 C++ 风格

c++ - C++ 和 QML 的对象顺序创建 QT

c++ - 模板类中的静态非模板方法

c++ - 如何在 GCC 中使用 pragma 指令禁用所有警告

linux - 在 RHEL4 中安装 GCC 3.4.6

c++ - "Operation not permitted"尝试执行已编译的 C++

c++ - 如何使用 qt 和 c++ 在 .bin 中编写二进制(而不是十六进制)?