使用 constexpr 变量禁用函数模板特化或重载
disable function template specialization or overload with constexpr variable
我在上游库中有一个我想要专门化的模板函数:
/// glog/logging.h
namespace google {
template <typename T>
inline void MakeCheckOpValueString(std::ostream* os, const T& v) {
(*os) << v;
}
} // namespace google
我通过在我的代码中定义来做到这一点
namespace google {
template <>
inline void MakeCheckOpValueString<std::chrono::nanoseconds>(std::ostream* os, const Duration& d) {
(*os) << v.cound();
}
} // namespace google
我想在编译时禁用此特化(即不通过预处理器宏),使用
中的某些内容
constexpr bool provide_my_specializations = ...;
template <std::enable_if<provide_my_specializations>>
inline void MakeCheckOpValueString<std::chrono::nanoseconds>(std::ostream* os, const Duration& d)
但我没有找到将 enable_if
放入模板专业化的方法。是否可以 enable/disable 使用 sfinae 进行模板专业化, 无需 修改通用模板?
编辑:
鉴于评论,我尝试使用函数重载,但未能找到禁用 sfinae 的正确位置
constexpr bool SWITCH = false;
namespace glog {
inline std::enable_if_t<SWITCH, void> MakeCheckOpValueString(std::ostream* os, const Duration& v) {
(*os) << v.count();
}
}
编辑 2:
我尝试专门化的函数不是我使用的,而是在上游库本身中使用的,所以我不能调用不同的(包装)对象,因为这需要编辑上游的调用站点。
(事实证明,这使得重载而不是专业化变得更加棘手 - 虽然并非不可能
// glog/logging.h
namespace google {
template <typename T>
inline void MakeCheckOpValueString(std::ostream* os, const T& v) {
(*os) << v;
}
tempate <typename T1, typename T2>
std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext) {
base::CheckOpMessageBuilder comb(exprtext);
MakeCheckOpValueString(comb.ForVar1(), v1);
MakeCheckOpValueString(comb.ForVar2(), v2);
return comb.NewString();
}
// my code
// non-templated overload of MakeCheckOpValueString needs to go here
#include <glog/logging.h>
// template specialization of MakeCheckOpValueString can go here
/*
code that eventually instantiates MakeCheckOpString comes here
*/
)
在这段代码中,如果你使用像代理 class 这样的包装器,你可以控制专业化,它可以通过 active_sp 变量进行控制。
using namespace std;
constexpr bool active_sp = true;
template <typename T>
struct hello
{
void operator()()
{
cout << "hello" << endl;
}
};
struct SomeOtherType{};
template <template <typename> class m, typename T, bool active = active_sp>
struct Proxy
{
void operator()()
{
m<T>()();
}
};
template <template <typename> class m>
struct Proxy<m, SomeOtherType, true>
{
void operator()()
{
cout << "hi" << endl;
}
};
template <template <typename> class m, typename T>
struct Proxy<m, T, false>
{
void operator()()
{
m<T>()();
}
};
int main()
{
hello<int>()();
Proxy<hello, int>()();
Proxy<hello, SomeOtherType>()();
return 0;
}
std::enable_if_t<false>
无效(对于任何专业)。
为了使 SFINAE 友好,您必须使条件依赖:
constexpr bool SWITCH = false;
namespace glog {
template <bool b = SWITCH>
std::enable_if_t<b> MakeCheckOpValueString(std::ostream* os, const Duration& v) {
(*os) << v.count();
}
}
我在上游库中有一个我想要专门化的模板函数:
/// glog/logging.h
namespace google {
template <typename T>
inline void MakeCheckOpValueString(std::ostream* os, const T& v) {
(*os) << v;
}
} // namespace google
我通过在我的代码中定义来做到这一点
namespace google {
template <>
inline void MakeCheckOpValueString<std::chrono::nanoseconds>(std::ostream* os, const Duration& d) {
(*os) << v.cound();
}
} // namespace google
我想在编译时禁用此特化(即不通过预处理器宏),使用
中的某些内容constexpr bool provide_my_specializations = ...;
template <std::enable_if<provide_my_specializations>>
inline void MakeCheckOpValueString<std::chrono::nanoseconds>(std::ostream* os, const Duration& d)
但我没有找到将 enable_if
放入模板专业化的方法。是否可以 enable/disable 使用 sfinae 进行模板专业化, 无需 修改通用模板?
编辑:
鉴于评论,我尝试使用函数重载,但未能找到禁用 sfinae 的正确位置
constexpr bool SWITCH = false;
namespace glog {
inline std::enable_if_t<SWITCH, void> MakeCheckOpValueString(std::ostream* os, const Duration& v) {
(*os) << v.count();
}
}
编辑 2:
我尝试专门化的函数不是我使用的,而是在上游库本身中使用的,所以我不能调用不同的(包装)对象,因为这需要编辑上游的调用站点。
(事实证明,这使得重载而不是专业化变得更加棘手 - 虽然并非不可能
// glog/logging.h
namespace google {
template <typename T>
inline void MakeCheckOpValueString(std::ostream* os, const T& v) {
(*os) << v;
}
tempate <typename T1, typename T2>
std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext) {
base::CheckOpMessageBuilder comb(exprtext);
MakeCheckOpValueString(comb.ForVar1(), v1);
MakeCheckOpValueString(comb.ForVar2(), v2);
return comb.NewString();
}
// my code
// non-templated overload of MakeCheckOpValueString needs to go here
#include <glog/logging.h>
// template specialization of MakeCheckOpValueString can go here
/*
code that eventually instantiates MakeCheckOpString comes here
*/
)
在这段代码中,如果你使用像代理 class 这样的包装器,你可以控制专业化,它可以通过 active_sp 变量进行控制。
using namespace std;
constexpr bool active_sp = true;
template <typename T>
struct hello
{
void operator()()
{
cout << "hello" << endl;
}
};
struct SomeOtherType{};
template <template <typename> class m, typename T, bool active = active_sp>
struct Proxy
{
void operator()()
{
m<T>()();
}
};
template <template <typename> class m>
struct Proxy<m, SomeOtherType, true>
{
void operator()()
{
cout << "hi" << endl;
}
};
template <template <typename> class m, typename T>
struct Proxy<m, T, false>
{
void operator()()
{
m<T>()();
}
};
int main()
{
hello<int>()();
Proxy<hello, int>()();
Proxy<hello, SomeOtherType>()();
return 0;
}
std::enable_if_t<false>
无效(对于任何专业)。
为了使 SFINAE 友好,您必须使条件依赖:
constexpr bool SWITCH = false;
namespace glog {
template <bool b = SWITCH>
std::enable_if_t<b> MakeCheckOpValueString(std::ostream* os, const Duration& v) {
(*os) << v.count();
}
}