模板参数在 int 上参数化的模板函数
Template function with template argument parametrized over int
不使用 C++11 及更高版本的功能(我会接受它们,但更喜欢 C++98),
我必须编写一个带有参数 T 的模板函数,它是 int
s 的 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
。
#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
来解决它。
#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);
}
不使用 C++11 及更高版本的功能(我会接受它们,但更喜欢 C++98),
我必须编写一个带有参数 T 的模板函数,它是 int
s 的 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
。
#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
来解决它。
#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);
}