模板参数在 int 上参数化的模板函数

Template function with template argument parametrized over int

不使用 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 参数始终是一个 class 模板,该模板在整数上进行参数化...我尝试编写 T<int> 但它仍然没有编译。

[注意] 本回答使用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++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;
}

template <template<int> class T> 不是你所期望的。

你想要

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::vector 不匹配 Container,因为它有额外的模板参数(Allocator,这是默认的)。

您可以添加重载:

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

C++11 允许 template <template <typename...> 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);
}