我正在尝试让一个函数采用泛型std::vector (template<typename T> std::vector<T>
,然后调用一个模板函数,该函数在其所有元素上都具有特定(抽象(类型的专用化。
我试图弄清楚如何使用专用版本,同时仍然能够使用通用版本,但我没有成功。
我正在使用Visual Studio 2019。
这是我的代码:
#include <iostream>
#include <vector>
//the abstract type
struct Foo
{
virtual int bar(unsigned int) const = 0;
};
//The 'template function' I mentioned
template<typename T>
void do_something_with_an_element(const T& value)
{
std::cout << value;
}
//the specialised version I mentioned
template<>
void do_something_with_an_element<Foo>(const Foo& value)
{
//Note: this is only a placeholder
std::cout << "It's a foo. bar = " << value.bar(7) << std::endl;
}
//the function that takes the 'generic' std::vector
template<typename T>
void do_something_with_a_vector(const std::vector<T>& vec)
{
for (auto element : vec)
{
//calling the function on all its elements
do_something_with_an_element(element); //Here is the problem line
}
}
struct foo_impl : public Foo
{
int val;
foo_impl(int _val)
: val(_val)
{}
// Inherited via Foo
virtual int bar(unsigned int _something) const override
{
//do whatever...
return val;
}
};
std::vector<int> int_vector = { 32, 3, 43, 23 };
std::vector<foo_impl> foo_vector = { foo_impl(3), foo_impl(9), foo_impl(13) };
int main()
{
do_something_with_a_vector(int_vector); //fine
do_something_with_a_vector(foo_vector); //compile error
}
这是我的错误:
1>program.cpp
1>C:...program.cpp(17): error C2679: binary '<<': no operator found which takes a right-hand operand of type 'const T' (or there is no acceptable conversion)
1> with
1> [
1> T=foo_impl
1> ]
1>C:...MSVC14.20.27508includeostream(438): note: could be 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(std::basic_streambuf<char,std::char_traits<char>> *)'
1>C:...MSVC14.20.27508includeostream(413): note: or 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(const void *)'
((list goes on...))
1>C:...program.cpp(17): note: while trying to match the argument list '(std::ostream, const T)'
1> with
1> [
1> T=foo_impl
1> ]
1>C:...program.cpp(35): note: see reference to function template instantiation 'void do_something_with_an_element<foo_impl>(const T &)' being compiled
1> with
1> [
1> T=foo_impl
1> ]
1>C:...program.cpp(61): note: see reference to function template instantiation 'void do_something_with_a_vector<foo_impl>(const std::vector<foo_impl,std::allocator<_Ty>> &)' being compiled
1> with
1> [
1> _Ty=foo_impl
1> ]
1>Done building project "program.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========```
为了选择const Foo&
的专业化,应该进行从foo_impl
到Foo
的隐式转换。另一方面,通过选择const T&
编译器会做一个聪明的举动,它直接推断出类型(即foo_impl
(,因为它对编译器来说更容易。
因此,Foo
的专业化被拒绝,并且出现了错误,因为没有发现operator<<(std::cout, foo_impl)
过载。
更新:为了选择正确的专用化,通过防止编译器实例化foo_impl
的const T&
,您可以使用SFINAE以及重载分辨率。(@Hiroki(
template<typename T>
std::enable_if_t<!std::is_base_of_v<Foo, T>>
do_something_with_an_element(const T& value)
{
std::cout << value;
}
void do_something_with_an_element(const Foo& value)
{
std::cout << "It's a foo. bar = " << value.bar(7) << std::endl;
}