禁用函数模板特化或使用constexpr变量重载

问题描述

我在上游库中有一个我想专门研究的模板化函数

/// 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放入模板专业化的方法。是否可以通过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();
}
}

compiler-explorer link

EDIT2:

我尝试使用的功能不是我专用的,而是在上游库中使用的,因此我不能调用其他(包装)对象,因为那样将需要在上游编辑调用站点

(事实证明,这使得重载而不是专业化变得棘手-虽然并非不可能

// 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
*/
)

解决方法

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();
}
}
,

在此代码中,如果您使用包装(如此处的代理类)可以通过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;
}