【问题标题】:Using a templated function parameter type name to call a function使用模板化函数参数类型名称调用函数
【发布时间】:2021-09-21 22:49:10
【问题描述】:

我正在使用为不同类型定义一些函数的 C API。比如:

// defined in a header:
extern "C" A* A_create();
extern "C" B* B_create();

是否可以从模板化的 C++ 函数调用这些函数,以便模板类型参数确定要调用的 C 函数?

类似:

// Template specialization for when T_create() exists
template <typename T>
auto create() -> declval( T##_create() ) {

    // This is not valid syntax, but I'd like to call A_create() if this
    // template is instantiated with A, B_create() if this is
    // instantiated with B, etc. If the function doesn't exist, I'd like
    // the compiler to fall back to the generic implementation below.
    return T##_create() 
}

// Template specialization for when T_create() doesn't exist
template <typename T>
T* create() { 
    return new T; // generic version just calls new. 
}

只是想知道是否可以在不对来自 C api 的每种类型的 create() 函数进行显式特化的情况下做到这一点。

【问题讨论】:

  • 不是模板,但也许你可以有一个从 typeid 到函数的std::map
  • 只有#define 宏可以从较小的部分创建标识符。
  • 您不能只混合使用deletefree,因此您需要跟踪是否使用了通用的new 版本,或者它是否真的是@987654329 的C 函数之一@ed 它让你知道以后如何释放内存。
  • @TedLyngmo 指出的问题可以通过使用 C 语言包装器专业化 return std::unique_ptr&lt;A, void(*)(A*)&gt;(A_create(), &amp;A_destroy); 或类似的以及默认模板只是 return std::make_unique&lt;T&gt;(); 来解决。当然,使用它们的代码可能需要在一些地方添加一些.get() 语法。

标签: c++ templates c++14 sfinae


【解决方案1】:

由于没有要使用的参数,我可能只使用具有特化的函数:

// generic version just calls new. 
template<class T>
T* create() { return new T;}
template<>
A* create() {return A_create();}
template<>
B* create() {return B_create();}

Then usage should be trivial:

A* ptr = create<A>();

你无法避免专业化,但你可以让它们变得简单。
#define make_lib_create(T) template<> \
T* create() {return T##_create();}
make_lib_create(A);
make_lib_create(B);

【讨论】:

  • 这可能是解决函数模板显式特化(而不是重载)的罕见情况之一。不需要结构。
  • @aschepler 我暂时忘记了允许完整的函数专业化
【解决方案2】:

您可以创建一个接受可调用对象作为参数的模板。以下示例提供了 2 个示例来说明如何实现 create 函数。

#include <iostream>
#include <memory>

struct A
{
    A() { std::cout << "A()\n"; }
    ~A() { std::cout << "~A()\n"; }
};

struct B
{
    B() { std::cout << "B()\n"; }
    ~B() { std::cout << "~B()\n"; }
};

std::unique_ptr<A> create_A()
{
    return std::make_unique<A>();
}

std::unique_ptr<B> create_B()
{
    return std::make_unique<B>();
}

template<typename C>
auto create(C createFn)
{
    return createFn();
}

template<typename T>
auto create2(T (*createFn)())
{
    return createFn();
}

int main()
{
    std::cout << "create()\n";
    {
        auto a = create(&create_A);
        auto b = create(&create_B);
    }
    
    std::cout << "create2()\n";
    {
        auto a = create2(&create_A);
        auto b = create2(&create_B);
    }

    return 0;
}

输出:

create()
A()
B()
~B()
~A()
create2()
A()
B()
~B()
~A()

【讨论】:

    猜你喜欢
    • 2018-10-23
    • 2017-03-25
    • 2021-05-31
    • 1970-01-01
    • 2020-05-28
    相关资源
    最近更新 更多