1

I have in an upstream library a templated function that I want to specialize:

/// glog/logging.h
namespace google {
  template <typename T>
  inline void MakeCheckOpValueString(std::ostream* os, const T& v) {
    (*os) << v;
  }
} // namespace google

I did so by defining in my code

namespace google {
  template <>
  inline void MakeCheckOpValueString<std::chrono::nanoseconds>(std::ostream* os, const Duration& d) {
    (*os) << v.cound();
  }
} // namespace google

I would like to disable this specialization at compile time (i.e. not through preprocessor macros) with something along the lines of

constexpr bool provide_my_specializations = ...;

template <std::enable_if<provide_my_specializations>>
  inline void MakeCheckOpValueString<std::chrono::nanoseconds>(std::ostream* os, const Duration& d)

But I didn't find a way where to put the enable_if into the template specialization. Is it possible to enable/disable a template specialization with sfinae, without modifying the general template?

EDIT:

given the comment, I tried using a function overload, though fail to find the right place for sfinae disabling either

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:

The function that I'm trying to specialize is not used by me, but in the upstream library itself, so I can't call a different (wrapping) object instead as that would require editing the call sites upstream.

(turns out that makes the overloading instead of specialization trickier - while not impossible

// 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
*/
)
pseyfert
  • 3,263
  • 3
  • 21
  • 47
  • Don't specialize. Instead, add an overload. template function specializations should be avoided. – NathanOliver Oct 07 '20 at 12:20
  • @NathanOliver okay, does that allow pushing compile time removal of the definition in? (included my attempt in the edit) – pseyfert Oct 07 '20 at 12:32
  • check this link https://stackoverflow.com/questions/10184824/why-does-this-dependent-type-not-count-as-specialization-using-the-template-argu – bakaDev Oct 07 '20 at 13:17
  • @bakaDev I might be missing something in that post but i don't see where that explains the disabling of the specialization(/overload) through complie time bools. – pseyfert Oct 07 '20 at 17:33
  • @NathanOliver care to elaborate (or reference) the advantages of overloading vs template specialization? I noticed in the concrete case, template specialization gives a bit more liberty about where to put the definition (and thus downstream of me no worries about include orders) – pseyfert Oct 07 '20 at 19:02
  • 1
    @pseyfert See: http://www.gotw.ca/publications/mill17.htm also https://stackoverflow.com/a/52760860/4342498 – NathanOliver Oct 07 '20 at 19:06

2 Answers2

2

std::enable_if_t<false> is invalid (for any specialization).

To make it SFINAE friendly, you have to make the condition dependent:

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();
}
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • Given what I noticed in edit2 (sensitivity to where my overload/specialization would need to go), I would prefer a specialization of the upstream template over an overload (so i can pack my implementation into a header and don't need to worry about include orders). Is there also a solution with template specialization? – pseyfert Oct 07 '20 at 19:05
  • I would say `std::conditional_t>`, so overload still exist but for dummy types. – Jarod42 Oct 07 '20 at 20:22
0

in this code you can control specialization if you use a wrapper like the proxy class in here that is control able via the active_sp variable.

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;
}
bakaDev
  • 367
  • 2
  • 7