【问题标题】:c++ how to take the address of the template function instance?c++如何取模板函数实例的地址?
【发布时间】:2019-01-03 07:45:17
【问题描述】:

抱歉代码不重要(也在 wandbox here 上)

#include <memory>
#include <cstdio>

template< typename T, size_t N, typename ... Args >
 void test_1 ( Args ... args)
 {
    using namespace std;

    if constexpr( 1 > (sizeof... (args))  ) {
         return;
    }
    else 
    {
    auto    arg_list [[maybe_unused]] = { args ... };
    }
 }
    template< typename T, size_t N, typename ... Args >
    void test_2 ( Args ... args)
    {
      auto  arg_list [[maybe_unused]] = { args ... };
    }
  ///////////////////////////////////////////////////////////
 int main()
 {
     test_1<int,3>(1,2,3);
     test_2<int,3>(1,2,3);

// taking the function pointer (aka address of) leads to
// full instantiation of function template 
constexpr auto adr_1 [[maybe_unused]] = std::addressof(test_1<int,3>);
// no can do --> constexpr auto adr_2 = std::addressof(test_2<int,3>);

}

所以。从上面可以看出,获取模板函数指针(也称为地址)会导致函数模板的完整实例化。

这有点不幸。如果一个人使用模板函数实例化的地址,那将产生一个完整的实例化。即使那个永远不会被调用。

     // pointer to instance made but instance never used
     constexpr auto adr_5 [[maybe_unused]] = std::addressof(test_1<float,9>);
     // pointer to instance made but instance never used
     constexpr auto adr_of_big_foot_gun 
           [[maybe_unused]] = std::addressof(test_1<bool,99>);
     // pointer to instance made but instance never used
     constexpr auto adr_of_crazy [[maybe_unused]] = 
                 std::addressof(test_1<char, 0xFFFF>);

现在。如何避免这种情况?请注意上面的代码意味着编译器会这样做:

        // this line
        std::addressof( test_2<int,3> )

        // provokes something like this
        // which needs to be compiled
        test_2<int,3>(void) ;

这就是为什么可以取上面test1的地址,但不能取test_2的原因。也许对我来说,这根本没有任何意义。通过这个,我的具体意思是编译函数模板实例,就好像通过使用 void 参数调用它一样?这反过来意味着,如果没有constexpr-if,将很难在上面写 test_1。这反过来(几乎)意味着没有 c++11 也没有 c++14。

请讨论...

【问题讨论】:

  • 没有办法绕过这个。某些东西需要存在才能有地址。您究竟希望您的未实例化函数模板特化的地址是什么?
  • 那么,你想避免实例化,但是你期望什么指针值呢?你只需要函数类型吗?
  • 您是否尝试进行诸如“函数在调用函数指针时实例化”之类的优化?如果是这样,这是不可能的,因为 c++ 仅在编译时执行此技巧。如果您对adr_1 == nullptr 没问题,那么只需typedef 您的函数指针类型并将其分配给nullptr
  • 是的,这正是一个相当不错的东西。在编译器中。
  • 注意std::addressof( test_1&lt;int,3&gt; ) != std::addressof( test_1&lt;int,3, char&gt; ),所以无效test_2&lt;int,3&gt;的地址无论如何都没用。

标签: c++ function templates pointers


【解决方案1】:

这有点不幸。如果使用模板的地址 函数实例化,这将产生一个完整的实例化。

这并不不幸。这就是语言的工作方式。如果你得到一个模板函数的地址(从函数模板实例化的函数),这个函数必须存在。也就是说,它必须从对应的函数模板中实例化出来。

如何避免这种情况?

没有办法。这是一种非常合理的预期行为。

【讨论】:

  • 感谢您的回答。也许对我来说,这根本没有任何意义。通过这个,我的具体意思是编译有趣的模板实例,就好像通过使用 void 参数调用它一样。这反过来意味着,如果没有constexpr-if,将很难写出上面的 test_1。这反过来(几乎)意味着没有 c++11 也没有 c++14。
  • @Edgar Rokjan “你不能专门化函数模板”。我觉得你可以? de.cppreference.com/w/cpp/language/template_specialization
  • @phön 我丢失了一个重要的词:部分。非常感谢您的评论!
  • @phön,我从问题中删除了“专业化”一词,因为它与 Edgar 正确的用例无关。
  • 函数模板就是这样:一个模板。在实例化之前,它不存在于实际程序中。您不能获取不存在的东西的地址。如果您不想实例化某些特定版本的模板函数,您可以传递这些类型参数:test_2&lt;int, 3, char, double, int&gt;
【解决方案2】:

为了取一个地址,你需要一个完整的实例化,否则没有什么可以指向的。请记住,编译器不会在运行时完成部分参数化模板的生成。即使在只知道函数指针的不同调用站点,编译器也无法实例化模板,因为它可能不知道。

test2&lt;int, 3, ...&gt;(或test1)的实例是不同的函数,根据参数的不同,它们永远不可能有一个地址。例如,test2&lt;int,3, int&gt;test2&lt;int, 3, int, int&gt; 不同,它接受不同的参数并用它们做不同的事情。它们的地址不同,对应的函数指针的类型也不同。

可能,根据您使用地址的方式,您可以在编译时通过模板参数化(如果指针本身是已实例化或未实例化的模板的一部分)或 constexpr-if 构造来关闭它们。

同样,如果在所有目标文件中都没有对指针的任何引用,链接器可能会使用正确的选项删除不必要的实例化模板,但这不能保证,您仍然需要支付编译费用时间成本。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    • 1970-01-01
    • 2011-12-01
    • 1970-01-01
    • 2011-10-07
    • 1970-01-01
    相关资源
    最近更新 更多