【问题标题】:Template function with template argument parametrized over int通过 int 参数化模板参数的模板函数
【发布时间】:2021-12-27 16:30:51
【问题描述】:

不使用 C++11 及更高版本的特性(我会接受但更喜欢 C++98),

我必须编写一个带有参数 T 的模板函数,它是ints 的 STL 容器。它接收这样一个容器以及它试图搜索的另一个int

现在我有这个,但它不能编译:

template <template<int> class T>
T::iterator easyfind(T &container, int val)
{
    T::iterator it = container.begin();
    for ( ; it != container.end(); it++)
        if (val == *it)
            break ;
    return (it);
}

我想知道我是否可以以某种方式强制 T 参数始终是一个通过整数参数化的类模板...我尝试编写 T&lt;int&gt; 但它仍然无法编译。

【问题讨论】:

  • 没有在for循环外声明的变量。
  • 谢谢,纠正错误

标签: c++ templates


【解决方案1】:

[NOTE] 此答案使用 C++20。 @PatrickRoberts 让我注意到您最好请求 C++98 解决方案。我还是把它留下,因为它可能对你有任何帮助。

你可以为你的模板添加一个需求,检查容器的类型是int

[Demo]

#include <iostream>  // cout
#include <list>
#include <type_traits>  // is_same
#include <vector>

template <typename C>
requires std::is_same<typename C::value_type, int>::value
auto easyfind(const C& container, int val)
{
    for (auto it{std::cbegin(container)}; it != std::cend(container); ++it)
    {
        if (val == *it) { return it; }
    }
    return std::cend(container);
}

int main()
{
    std::vector<int> vi{1, 2, 3};
    if (auto it{easyfind(vi, 2)}; it != std::cend(vi))
    {
        std::cout << *it << "\n";
    }

    std::list<int> li{4, 5, 6};
    if (auto it{easyfind(li, 8)}; it != std::cend(li))
    {
        std::cout << *it << "\n";
    }

    std::vector<double> vd{0.5, 1.3, 2.8};
    //if (auto it{easyfind(vd, 1.3)}; it != std::cend(vd))  // error
    //{
    //    std::cout << *it << "\n";
    //}
}

【讨论】:

  • 约束是 C++20 的特性,如果 OP 要求使用 C++98,我怀疑它会被支持。
  • @PatrickRoberts 非常感谢您告诉我! OP的问题很清楚,但我没看。
【解决方案2】:

虽然有一个公认的答案,但让我尝试使用C++98 解决它。

DEMO

#include <vector>
#include <iostream>

namespace details{
    struct true_type{static const bool value = true;};
    struct false_type{static const bool value = false;};

    template<typename T1,typename T2> struct is_same : false_type{};
    template<typename T> struct is_same<T,T>:true_type{};

    #define STATIC_ASSERT(expr, msg)               \
    {                                              \
        char STATIC_ASSERT##msg[(expr)?1:-1]; \
    }
};

template <class T>
typename T::iterator easyfind(T &container, int val)
{
    using namespace details;
    //static_assert can be used in C++11 onwards
    STATIC_ASSERT((is_same<typename T::value_type,int>::value == true_type::value),InavalidType);

    typename T::iterator it = container.begin();
    for ( ; it != container.end(); it++)
        if (val == *it)
            break ;
    return (it);
}


int main(){

    std::vector<int> a{1,2,3};

    auto it = easyfind(a,1);

    if(it != a.end())
        std::cout<<*it<<std::endl;

    auto it2 = easyfind(a,4);

    if(it2 != a.end())
        std::cout<<*it<<std::endl;
    else
        std::cout<<"Not Found"<<std::endl;

    std::vector<double> b{1.0,2.0,3.0};

   // std::vector<int>::iterator it3 = easyfind(b,1.0); //error

    return 0;
}

【讨论】:

  • 这很有趣,谢谢!!
【解决方案3】:

template &lt;template&lt;int&gt; class T&gt; 不是你所期望的。

你想要

template <template <typename> class Container>
typename Container<int>::iterator easyfind(Container<int> &container, int val)
{
#if 1 // Your code
    typename Container<int>::iterator it = container.begin();
    for ( ; it != container.end(); it++)
        if (val == *it)
            break ;
    return it;
#else // code with <algorithm>
    return std::find(container.begin(), container.end(), val);
#endif
}

很遗憾,std::vectorContainer 不匹配,因为它有额外的模板参数(分配器,默认设置)。

您可以添加重载:

template <template <typename, typename> class Container, typename Alloc>
typename Container<int, Alloc>::iterator easyfind(Container<int, Alloc> &container, int val)

C++11 将允许template &lt;template &lt;typename...&gt; class Container

更简单的方法是直接使用容器作为类型:

template <typename Container>
#if 1 // No SFINAE
typename Container::iterator
#else // SFINAE with traits from C++11, which can be written trivially in C++98
typename std::enable_if<std::is_same<int, typename Container::value_type>>::type
#endif
easyfind(Container& container, int val)
{
#if 1 // Your code
    typename Container::iterator it = container.begin();
    for ( ; it != container.end(); it++)
        if (val == *it)
            break ;
    return it;
#else // code with <algorithm>
    return std::find(container.begin(), container.end(), val);
#endif
}

但更通用的是完全放弃 int 要求:

template <typename Container>
typename Container::iterator
easyfind(Container& container, typename Container::const_reference val)
{
    return std::find(container.begin(), container.end(), val);
}

【讨论】:

    猜你喜欢
    • 2018-06-02
    • 2013-08-02
    • 2011-05-27
    • 1970-01-01
    • 2010-09-18
    • 2018-10-23
    • 1970-01-01
    • 2015-06-29
    • 1970-01-01
    相关资源
    最近更新 更多