【问题标题】:Inferring template parameters推断模板参数
【发布时间】:2015-02-26 18:30:02
【问题描述】:

我正在尝试编写一个函数模板来推断其大部分参数,以实现简单的查找表。

但是,我的努力始终出现编译器错误。 这是我迄今为止最好的尝试:

// A simple templated struct that maps one key to one value
template<typename KT, typename VT>
struct LookupTable
{
    KT key;
    VT value;
};

// A lookup function that searches an array for a match.
// returns NULL if key was not found.
// returns pointer to matching value when key is found.
//
// The first parameter is a Reference to an Array of T, with a specific size N
// In this example, the size is 12.
template<typename T, size_t N, typename KT, typename VT>
VT* Find(T<KT,VT> (&A)[N], KT key)   // <== Multiple Errors on this line
{
    VT* pFoundValue = NULL;
    for (size_t i = 0; i < N; ++i)
    {
        if (key == A[i].key)
        {
            pFoundValue = &(A[i].value);
            break;
        }
    }
    return pFoundValue;
}

// Test the function with a simple example
int main(void)
{
    LookupTable<std::string, int> calendar[] = {
        { "January",   31 },
        { "February",  28 },
        { "March",     31 },
        { "April",     30 },
        { "May",       31 },
        { "June",      30 },
        { "July",      31 },
        { "August",    31 },
        { "September", 30 },
        { "October",   31 },
        { "November",  30 },
        { "December",  31 }
    };

    const int* pDays = Find(calendar, std::string("May"));

    if (pDays == NULL)
    {
        cout << "Invalid Month" << endl;
    }
    else
    {
        cout << "The month of May has " << *pDays << " Days" << endl;
    }

    _getch();
    return 0;
}

我得到的错误都在Find函数的声明上
(标有注释)

1>error C2143: syntax error : missing ')' before '<'
1>error C2143: syntax error : missing ';' before '<'
1>error C2988: unrecognizable template declaration/definition
1>error C2059: syntax error : '<'
1>error C2059: syntax error : ')'
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

看来我已经使所有参数都易于从函数调用中推断出来。
我是否有遗漏的语法错误?

【问题讨论】:

  • T作为模板模板参数,所以声明为:template class T

标签: c++ templates type-inference


【解决方案1】:

在这个:

template<typename T, size_t N, typename KT, typename VT>
VT* Find(T<KT,VT> (&A)[N], KT key)

您正在尝试使用T 作为模板模板参数。语法是:

template<template <class, class> class T, size_t N, typename KT, typename VT>
VT* Find(T<KT,VT> (&A)[N], KT key)

【讨论】:

  • 这个语法至少可以编译...现在测试验证。谢谢!
  • 我的最终语法是:template&lt;template &lt;typename, typename&gt; class T, size_t N, typename KT, typename VT&gt;。非常接近你所拥有的,但不完全是。谢谢!
  • @abelenky 在那里使用typenameclass 没有区别。但是,typename 确实与您签名的其余部分更加一致。
  • typenameclass还是有区别的。如果我尝试将class 部分更改为typename,则会出现编译器错误。最后的class 实际上是class 似乎很重要(而不是structtypename
  • @abelenky 是的,我的“那里”没有足够的信息 :) typenameclass 在引用类型模板参数时可以互换 - template&lt;class, class&gt; class Ttemplate &lt;typename, typename&gt; class T 是相同的事物。但是,在 C++17 之前,您只能使用 class 来引用模板模板参数(在您的示例中为 T)。所以,在那之前,template &lt;class, class&gt; typename T 失败了。
【解决方案2】:

代替

template<typename T, size_t N, typename KT, typename VT>
VT* Find(T<KT,VT> (&A)[N], KT key)

使用

template<template <typename, typename> class T, size_t N, typename KT, typename VT>
        //^^^^^^^^^^^^^^^^^^^ Need to indicate that T is a class template
VT* Find(T<KT,VT> (&A)[N], KT key)

【讨论】:

    【解决方案3】:

    这是一个更紧凑、对 SFINAE 友好的版本,可以编译。请注意,我已经声明了数组参数const,因为它不需要修改。

    #include <type_traits>
    
    template<typename PairT,
             typename KeyT = decltype(std::declval<PairT>().key),
             typename ValueT = decltype(std::declval<PairT>().value),
             std::size_t N>
    const ValueT *
    Find(const PairT (&array)[N], KeyT key)
    {
      for (auto& iter : array)
        if (key == iter.key)
          return &(iter.value);
      return nullptr;
    }
    

    当然,这可以使用 STL 算法进一步简化,这也将避免为查找键创建 std::string 临时。

    auto pred = [](const LookupTable<std::string, int>& cal){
      return cal.key == "May";
    };
    auto pDays = std::find_if(std::begin(calendar), std::end(calendar), pred);
    if (pDays == std::end(calendar))
      std::cout << "Invalid Month" << std::endl;
    else
      std::cout << "May has " << (*pDays).value << " days" << std::endl;
    

    【讨论】:

    • 这正是我想要的。不过,我不知道我可以用 C++ 做到这一点。
    【解决方案4】:

    试试这个格式:

     template<size_t N, typename KT, typename VT, template<typename, typename> class T>
    

    【讨论】:

      猜你喜欢
      • 2022-12-02
      • 1970-01-01
      • 2023-03-31
      • 2013-02-18
      • 1970-01-01
      • 1970-01-01
      • 2017-03-22
      • 2020-07-01
      相关资源
      最近更新 更多