是否可以根据模板参数专门化命名空间?

huangapple go评论74阅读模式
英文:

Is it possible to specialize a namespace depending on the template argument?

问题

这是我想要得到的内容。调用者无法访问B命名空间。

template<typename T>
A::T foo1(std::vector<std::uint8_t> const& data)
{
  return foo2<B::T>(data);
}

T是在AB中以不同方式定义的类型。我尝试解决这个问题,但似乎唯一可行的解决方案是像这样重载它:

void foo1(A::typeX& out, std::vector<std::uint8_t> const& data)
{
  out = foo2<B::typeX>(data);
}

void foo1(A::typeY& out, std::vector<std::uint8_t> const& data)
{
  out = foo2<B::typeY>(data);
}

这是一个不错的解决方案,但每当需要处理新类型(比如typeZ)时,就需要添加一个新函数(请注意,将out参数传递为引用是重载的唯一方法,因为我不能使重载的函数直接返回它,因为它们唯一的区别是返回类型,这是不允许的)。再次强调,调用者只知道A命名空间,因此无法直接调用foo2()

我正在使用的C++标准是C++14(允许实验性命名空间)。

希望我表达足够清楚。谢谢!

我尝试映射输入/输出类型,但最终没有找到可行的解决方案,我和团队的其他成员也不喜欢那种方法。

我期望找到一种解决方法,使第一个代码片段工作(当然,不是我写的方式)。总的来说,我正在尝试专门化一个命名空间:如果输入参数类型是A::typeX,那么我使用B::typeX命名空间,否则如果输入参数类型是A::typeY,那么我使用B::typeY命名空间。

最好(请注意,最好)我希望找到一种不需要预定义映射的解决方案。

英文:

This is what I would like to get. The caller does not have access to B namespace.

template&lt;typename T&gt;
A::T foo1(std::vector&lt;std::uint8_t&gt; const&amp; data)
{
  return foo2&lt;B::T&gt;(data);
}

T is a type defined (in different ways) both in A and B. I tried to solve this problem but the only solution that seems feasible is to overload it like this:

    void foo1(A::typeX&amp; out, std::vector&lt;std::uint8_t&gt; const&amp; data)
    {
      out = foo2&lt;B::typeX&gt;(data);
    }

    void foo1(A::typeY&amp; out, std::vector&lt;std::uint8_t&gt; const&amp; data)
    {
      out = foo2&lt;B::typeY&gt;(data);
    }

It is a good solution but it requires a new function to be added every time a new type (say typeZ) needs to be handled (notice that passing the out parameter as a reference is the only way to overload it as I cannot make the overloaded functions return it directly since they would differ only for the returned type, and this is not permitted). Again, the caller only knows about A namespace, so it cannot call foo2() directly.

The standard of C++ I'm using is C++14 (experimental namespaces allowed)

I hope I,ve been clear enough. Thank you!

I tried to map the input/output type but I didn't end up with a working solution and neither me neither the rest of the team liked that.

I'm expecting to find a workaround to make the first code snippet working (of course, not exactly in the way I wrote it). In general, I'm trying to specialise a namespace: if the input parameter type is A::typeX then I use the B::typeX namespace, otherwise if the input parameter type is A::typeY then I use the B::typeY namespace.

Preferably (notice, preferably) I'd like a solution that doesn't require predefined mappings.

答案1

得分: 1

根据你的要求,以下是代码部分的中文翻译:

唯一的方法,据我所知,是使用某种类型映射,要么使用std::conditional,要么使用模板特化。

// std::conditional
template<class T>
using b_type_t = typename std::conditional<
    std::is_same<T, A::typeX>::value, B::typeX,
    typename std::conditional<
        std::is_same<T, A::typeY>::value, B::typeY, 
        ...>::type>::type;

// 模板特化
template<class T>
struct b_type { };
template<class T>
using b_type_t = typename b_type<T>::type;

template<> struct b_type<A::typeX> { using type = B::typeX; }
template<> struct b_type<A::typeY> { using type = B::typeY; }
....

然后在函数中使用这个映射:

template<typename AType>
AType foo1(std::vector<std::uint8_t> const& data)
{
    return foo2<b_type_t<AType>>(data);
}

如果B中的类型与A中的类型相同,那么你可以将这些类型导入到A而不是定义相同的结构体。

// 导入整个命名空间
namespace A {
using namespace B;
}

// 或者只导入类型
namespace A {
using B::typeX;
using B::typeY;
....
}

// 然后直接使用这些类型
template<typename T>
T foo1(std::vector<std::uint8_t> const& data)
{
    return foo2<T>(data);
}
英文:

The only way to do this AFAIK is to use some kind of type map, either by using std::conditional or template specialization.

// std::conditional
template&lt;class T&gt;
using b_type_t = typename std::conditional&lt;
    std::is_same&lt;T, A::typeX&gt;::value, B::typeX,
    typename std::conditional&lt;
        std::is_same&lt;T, A::typeY&gt;::value, B::typeY, 
        ...&gt;::type&gt;::type;

// template specialization
template&lt;class T&gt;
struct b_type { };
template&lt;class T&gt;
using b_type_t = typename b_type&lt;T&gt;::type;

template&lt;&gt; struct b_type&lt;A::typeX&gt; { using type = B::typeX; }
template&lt;&gt; struct b_type&lt;A::typeY&gt; { using type = B::typeY; }
....

And then use the map in the functions

template&lt;typename AType&gt;
AType foo1(std::vector&lt;std::uint8_t&gt; const&amp; data)
{
    return foo2&lt;b_type_t&lt;AType&gt;&gt;(data);
}

If the types in B are identical to the types in A then you can import the types into A instead of defining identical structs.

// import the entire namespace
namespace A {
using namespace B;
}

// or import only the types
namespace A {
using B::typeX;
using B::typeY;
....
}

// Then use the types directly
template&lt;typename T&gt;
T foo1(std::vector&lt;std::uint8_t&gt; const&amp; data)
{
    return foo2&lt;T&gt;(data);
}

huangapple
  • 本文由 发表于 2023年7月17日 21:56:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/76705179.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定