如何根据实例化特征有条件地编码模板 function/class?
How to conditionally code a template function/class based on instantiation traits?
我提供的示例是虚假且毫无意义的,但它是对更复杂(和更逻辑)代码的简化。
代码
template<typename T>
void MyTemplate(T t)
{
wstringstream stringStream;
stringStream << t << endl;
// rest of the code
}
struct MyClass {};
void func()
{
MyTemplate(1); // OK
MyTemplate(MyClass()); // error C2679: binary '<<': no operator found which takes a right-hand operand of type 'T' (or there is no acceptable conversion)
}
问题
MyTemplate
是通用的,但不能用任何实例化进行编译。
问题
有没有办法按以下方式对 MyTemplate
进行编码:
void MyTemplate(T t)
{
wstringstream stringStream;
// if/directives/magic to check if object is stream-able do
stringStream << t << endl;
// else
stringStream << "object is not stream-able" << endl;
// rest of the code
}
是的。
首先,我们需要一个特征来检查给定类型是否可流式传输到给定流:
template<typename T, typename Stream, typename = void>
struct can_stream : std::false_type{};
template<typename T, typename Stream>
struct can_stream<T, Stream, std::void_t<decltype(std::declval<Stream>() << std::declval<T>())>> : std::true_type{};
在我们的工具箱中有了这个,我们可以在我们的函数中使用 if constexpr:
template<typename T>
void MyTemplate(T t)
{
wstringstream stringStream;
if constexpr(can_stream<T, std::wstringstream>::value)
{
stringStream << t << endl;
}
else
{
stringStream << "object is not stream-able" << endl;
}
}
就是这样。
为特征值提供 shorthand 是一种很好的做法:
template<typename T, typename Stream>
inline constexpr auto can_stream_v = can_stream<T, Stream>::value;
所以我们有了最终的工作示例:
#include <iostream>
#include <sstream>
#include <type_traits>
using namespace std;
template<typename T, typename Stream, typename = void>
struct can_stream : std::false_type{};
template<typename T, typename Stream>
struct can_stream<T, Stream, std::void_t<decltype(std::declval<Stream>() << std::declval<T>())>> : std::true_type{};
template<typename T, typename Stream>
inline constexpr auto can_stream_v = can_stream<T, Stream>::value;
template<typename T>
void MyTemplate(T t)
{
wstringstream stringStream;
if constexpr(can_stream_v<T, std::wstringstream>)
{
stringStream << t << endl;
}
else
{
stringStream << "object is not stream-able" << endl;
}
std::wcout << stringStream.str();
}
struct MyClass {};
int main()
{
MyTemplate(1);
MyTemplate(MyClass());
return 0;
}
我提供的示例是虚假且毫无意义的,但它是对更复杂(和更逻辑)代码的简化。
代码
template<typename T>
void MyTemplate(T t)
{
wstringstream stringStream;
stringStream << t << endl;
// rest of the code
}
struct MyClass {};
void func()
{
MyTemplate(1); // OK
MyTemplate(MyClass()); // error C2679: binary '<<': no operator found which takes a right-hand operand of type 'T' (or there is no acceptable conversion)
}
问题
MyTemplate
是通用的,但不能用任何实例化进行编译。
问题
有没有办法按以下方式对 MyTemplate
进行编码:
void MyTemplate(T t)
{
wstringstream stringStream;
// if/directives/magic to check if object is stream-able do
stringStream << t << endl;
// else
stringStream << "object is not stream-able" << endl;
// rest of the code
}
是的。 首先,我们需要一个特征来检查给定类型是否可流式传输到给定流:
template<typename T, typename Stream, typename = void>
struct can_stream : std::false_type{};
template<typename T, typename Stream>
struct can_stream<T, Stream, std::void_t<decltype(std::declval<Stream>() << std::declval<T>())>> : std::true_type{};
在我们的工具箱中有了这个,我们可以在我们的函数中使用 if constexpr:
template<typename T>
void MyTemplate(T t)
{
wstringstream stringStream;
if constexpr(can_stream<T, std::wstringstream>::value)
{
stringStream << t << endl;
}
else
{
stringStream << "object is not stream-able" << endl;
}
}
就是这样。 为特征值提供 shorthand 是一种很好的做法:
template<typename T, typename Stream>
inline constexpr auto can_stream_v = can_stream<T, Stream>::value;
所以我们有了最终的工作示例:
#include <iostream>
#include <sstream>
#include <type_traits>
using namespace std;
template<typename T, typename Stream, typename = void>
struct can_stream : std::false_type{};
template<typename T, typename Stream>
struct can_stream<T, Stream, std::void_t<decltype(std::declval<Stream>() << std::declval<T>())>> : std::true_type{};
template<typename T, typename Stream>
inline constexpr auto can_stream_v = can_stream<T, Stream>::value;
template<typename T>
void MyTemplate(T t)
{
wstringstream stringStream;
if constexpr(can_stream_v<T, std::wstringstream>)
{
stringStream << t << endl;
}
else
{
stringStream << "object is not stream-able" << endl;
}
std::wcout << stringStream.str();
}
struct MyClass {};
int main()
{
MyTemplate(1);
MyTemplate(MyClass());
return 0;
}