如何通过结构的成员推断模板

How to deduce template by struct's member

本文关键字:成员 何通过 结构      更新时间:2023-10-16

>假设我有一些结构,每个结构都包含一个枚举作为成员。 我想调用结构体的方法,但取决于结构体的成员,如代码示例中所示:

#include <iostream>
#include <string>
#include <type_traits> 
enum class Type{
lowercase = 0,
uppercase
};
struct Low{
static constexpr Type cp = Type::lowercase;
};
struct Up{
static constexpr Type cp = Type::uppercase;
};

template<typename Case, typename=void>
struct Printer
{
void print_g(const std::string& s){
std::cout << "just s: " << s << std::endl;
}
};
template<typename X>
struct Printer<X, std::enable_if_t<X::cp == Type::lowercase, void>>
{
void print_g(const std::string& s){
std::cout << "lowercase " << std::nouppercase << s << std::endl;
}
};
template<typename X>
struct Printer <X, std::enable_if_t<X::cp == Type::uppercase, void>>
{
void print_g(const std::string& s){
std::cout << "uppercase " << std::uppercase << s << std::endl;
}
};
int main()
{
Printer<Low> pl;
pl.print_g("hello1");
Printer<Up> p2;
p2.print_g("hello2");
}

但是这个解决方案对我来说看起来不太优雅。 尤其是第一个模板中的部分类型=void。 只有这样代码才会编译。为什么会这样呢? 对于此模板专业化,是否有更好(更优雅)的解决方案?

在 C++17 中,您可以使用if constexpr

template <typename X>
struct Printer
{
void print_g(const std::string& s)
{
if constexpr(X::cp == Type::lowercase)
{
std::cout << "lowercase " << std::nouppercase << s << std::endl;
}
else if constexpr(X::cp == Type::uppercase)
{
std::cout << "uppercase " << std::uppercase << s << std::endl;
}
else
{
std::cout << "just s: " << s << std::endl;
}
}
};

如果您无权访问 C++17,请考虑以下选项:

  • 使用常规if...else声明。在您的示例中,没有需要有条件地编译的代码。

  • 在 C++14 中实施static_if。以下是我给出的一个演讲,解释了如何做到这一点:在 C++14 中实现static控制流

您可以完全专注于LowUpPrinter

template<class Case>
struct Printer
{
void print_g(const std::string& s) {
std::cout << "just s: " << s << std::endl;
}
};
template<>
struct Printer<Low>
{
void print_g(const std::string& s) {
std::cout << "lowercase " << std::nouppercase << s << std::endl;
}
};
template<>
struct Printer<Up>
{
void print_g(const std::string& s) {
std::cout << "uppercase " << std::uppercase << s << std::endl;
}
};

请注意,枚举根本不起作用。如果您需要专门针对枚举,您也可以这样做。

template<Type Case>
struct PrinterHelper
{
void print_g(const std::string& s) {
std::cout << "just s: " << s << std::endl;
}
};
template<>
struct PrinterHelper<Type::lowercase>
{
void print_g(const std::string& s) {
std::cout << "lowercase " << std::nouppercase << s << std::endl;
}
};
template<>
struct PrinterHelper<Type::uppercase>
{
void print_g(const std::string& s) {
std::cout << "uppercase " << std::uppercase << s << std::endl;
}
};
template<class Case>
using Printer = PrinterHelper<Case::cp>;

我可能会选择:

enum struct Casing
{
Lower,
Upper
};
template<Casing>
struct printer;
template<>
struct printer<Casing::Lower>
{
...
};
template<>
struct printer<Casing::Upper>
{
...
};