从字符串文字中推导模板参数

Template Argument Deduction from String Literal

我目前正在考虑如何最好地将模板的泛型类型限制为 std::sting 以及字符串文字。因此,我使用 std::is_same 将推导的类型与所需的类型进行比较。在 std::string 的情况下,这会立即起作用。对于字符串字面量,即 char const 数组,只有在类型上使用 std::decay,然后将结果与类型 char const * 进行比较时,它才有效。如果我直接将推导的类型与我认为应该是的类型进行比较,is_same returns 错误,如以下示例代码所示。

template <class TYPE>
void function(TYPE&& parameter)
{
  //this doesn't work as expected
  std::cout << typeid(TYPE).name() << " : " << typeid(char const [5]).name() << std::endl;
  std::cout << std::is_same<char const [5], TYPE>::value << std::endl;
  //this works as expected
  std::cout << typeid(std::decay_t<TYPE>).name() << " : " << typeid(char const *).name() << std::endl;
  std::cout << std::is_same<char const *, std::decay_t<TYPE>>::value << std::endl;
}

int main(int argc, char** argv)
{
  function("name");
  return 0;
}

生成的输出如下:

char const [5] : char const [5]
0
char const * __ptr64 : char const * __ptr64
1

现在,我想知道为什么在第一种情况下 is_same returns false 即使类型看起来相同。

我能想到的唯一可能的解释是,在函数 std::is_same 中,对类型应用了类似于 std::decay 的转换(例如函数调用)。但是话又说回来,这种转换也会发生在另一种类型上,产生相同的结果,从而导致相等。

使用 gcc 自定义函数:

template < class T >
constexpr std::string type_name()
{
    std::string p = __PRETTY_FUNCTION__;
    return p.substr( 43 + 10, p.length() - 100 - 1 - 10 );
}

并将其添加到您的代码中:

std::cout << type_name<TYPE>() << " : " << type_name<char const [5]>() << std::endl;

结果是:

A5_c : A5_c
0
const char (&)[5] : const char [5]

因此您需要在 TYPE 上使用 std::remove_reference

可能是编译器的错误。编译器在编译时生成由 typeid 给出的此类类型对象。编译器不会为每个长度(0 到 2**n)编译数组类型,因此它会在需要时编译它们,并且它可能 "forget" 关于重复项。尝试使用特殊模板,将长度与包含的类型分开。这不是类型,但您可以检查它是否等于另一个类型。

    template<class T, size_t size> 
struct array_t{};

    template <class T, size_t size>
void function(T[size] parameter) {
    std::cout << typeid(array_t<T, size>).name() << " : " << typeid(array_t<char, 5>).name() << std::endl;
    std::cout << std::is_same<array_t<T, size>, array_t<char, 5>>::value << std::endl;
};

字符串文字不是按 char const [N] 的值传递,而是 referencechar const (&)[N].

这对我来说是正确的:

std::cout << std::is_same<char const (&)[5], TYPE>::value << std::endl;

注意here

1) Refers to a std::type_info object representing the type type. If type is a reference type, the result refers to a std::type_info object representing the referenced type.

您可以轻松地验证 is_same 不会像 type_info 一样丢弃引用性,例如通过检查

std::is_same<int&, int>::value == false

这解释了为什么 typeid 名称相同,但您的 is_same 测试仍然失败。