如何避免先验荒谬的重复模板专业化?

How to avoid a priori absurd duplicate template specialization?

提问人:bitmap kid 提问时间:10/18/2023 最后编辑:Adrian Molebitmap kid 更新时间:10/18/2023 访问量:106

问:

在下面的上下文中,有没有办法不使该方法专业化?请注意,它们几乎相同。这个例子故意很小。exec

就我而言,必须复制许多方法才能简单地更改演员表,这在使用模板时将是一个真正的悖论。也许做事的方式根本不是正确的?

#include <iostream>
using namespace std;

class D {
    public:
        D(uint8_t * mem) : m_mem(mem) {}
        uint8_t *m_mem;
        operator uint32_t*() { return reinterpret_cast<uint32_t*>(m_mem); }
};

template <typename T>
class C {
    public:
        C(T mem) : m_mem(mem) {}
        T m_mem;
        void exec();
};

template<>
void C<uint8_t*>::exec() {
    
    cout << "exec = " << *reinterpret_cast<uint32_t*>(m_mem) << endl;
}

template<>
void C<D>::exec() {
    
    cout << "exec = " << *static_cast<uint32_t*>(m_mem) << endl;
}

int main()
{
    uint8_t mem[4] = {0,1,2,3};
    
    C<uint8_t*> c1(mem);
    C<D>        c2(mem);
    
    c1.exec();
    c2.exec();

    return EXIT_SUCCESS;
}
C++ 模板 转换 C++20

评论

0赞 Igor Tandetnik 10/18/2023
写一个辅助模板,比如说,把演员表隐藏在那里,根据需要进行专业化。然后在等人中,称此助手为助手。AsUint32Ptrexec
0赞 perencia 10/18/2023
我不明白为什么你不能在 C<uint8_t*> 上进行静态强制转换
0赞 Caleth 10/18/2023
仅当是 (或 ) 的别名时,才定义了行为。为什么使用而不是在这里?uint8_tunsigned charcharuint8_tunsigned char
0赞 Igor Tandetnik 10/19/2023
@perencia 因为它不会编译。
0赞 perencia 10/19/2023
我想@IgorTandetnik,但为什么呢?

答:

2赞 Adrian Mole 10/18/2023 #1

在 C++20(及更高版本)中,可以在“constexpr if”语句中使用 convertible_to 概念,以选择要在单个函数模板中使用的强制转换类型。下面的代码替换了你的两个专业化exec

#include <concepts>
template<class T>
void C<T>::exec()
{
    if constexpr (std::convertible_to<T, uint32_t*>) {
        std::cout << "exec = " << *static_cast<uint32_t*>(m_mem) << std::endl;
    }
    else {
        std::cout << "exec = " << *reinterpret_cast<uint32_t*>(m_mem) << std::endl;
    }
}

在 C++20 之前(或者如果你想避免概念),有一个 std::is_convertible 类型特征,它将实现大致相同的目的:

#include <type_traits>
template<class T>
void C<T>::exec()
{
    if constexpr (std::is_convertible<T, uint32_t*>::value) {
        std::cout << "exec = " << *static_cast<uint32_t*>(m_mem) << std::endl;
    }
    else {
        std::cout << "exec = " << *reinterpret_cast<uint32_t*>(m_mem) << std::endl;
    }
}

评论

0赞 bitmap kid 10/19/2023
真的是一个很好的方法。如果有人想知道 if/else 的影响:在生成的二进制文件中没有它们的痕迹。
0赞 Adrian Mole 10/19/2023
@bitmapkid那是因为声明中的。constexprif
2赞 Igor Tandetnik 10/18/2023 #2

计算机科学中的大多数问题都可以通过添加间接级别来解决。也许有类似这样的东西:

uint32_t* AsUint32Ptr(uint8_t* mem) {
  return reinterpret_cast<uint32_t*>(mem);
}

uint32_t* AsUint32Ptr(D& mem) {
  return static_cast<uint32_t*>(mem);
}

有了它,你就不需要再专攻了:exec

template <typename T>
void C<T>::exec() {
    cout << "exec = " << *AsUInt32Ptr(m_mem) << endl;
}

评论

0赞 bitmap kid 10/19/2023
很棒的解决方案,感谢间接的概念。