16

I tried to implement an SFINAE using bool (unlike popular void_ trick):

  template<typename T, bool = true>
  struct Resolve
  {
    static const bool value = false;
  };

  template<typename T>
  struct Resolve<T, T::my_value>
  {
    static const bool value = true;
  };

The goal is to specialize, the classes which have static const bool my_value = true; defined inside it. If they are defined false or not defined then don't specialize it. i.e.

struct B1 {  // specialize Resolve for this case
  static const bool my_value = true;
};
struct B2 {  // don't specialize
  static const bool my_value = false;
};
struct B3 {};  // don't specialize

When applying the above trick on B1 it gives the compilation error:

Resolve<B1>::value;

error: template argument ‘T::my_value’ involves template parameter(s)

I am aware that this can be achieved with alternate ways. However, I am interested in knowing, why it gives compiler error here and can it be solved in this code itself ?

Community
  • 1
  • 1
iammilind
  • 68,093
  • 33
  • 169
  • 336

1 Answers1

34

Actually what you're doing is forbidden by section §14.5.4/9 which says,

A partially specialized non-type argument expression shall not involve a template parameter of the partial specialization except when the argument expression is a simple identifier.

The trick could be using a type for second template parameter as well, encapsulating the non-type value, as described below:

template<bool b> struct booltype {};

template<typename T, typename B = booltype<true> >
struct Resolve
{
  static const bool value = false;
};

template<typename T>
struct Resolve<T, booltype<T::my_value> >
{
  static const bool value = true;
};

Now it compile fines.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • Nice solution. I have edited some part and the example. For my specific requirement I wanted to explore `bool` trick rather than `void_` trick for SFINAE. Also, if it's forbidden by standard then, I think I should accept this answer, because I don't see any other way out. – iammilind Oct 15 '11 at 07:50
  • Well, the edit is okay. I thought you could use the member in `bool2type`, that is why I added it. But if you don't need it, then it is perfectly fine with me. – Nawaz Oct 15 '11 at 07:52
  • Ahh, this is exactly the solution I needed for my problem. [Question 15115109](http://stackoverflow.com/questions/15115109/how-to-convert-templated-function-overloads-to-partial-specialized-templated-cla) I took it a step further by using std::integral_constant< typename bool, bool b >, and those that are directly available via type_traits' "::type" member. – Charles L Wilcox Feb 27 '13 at 22:02
  • I adapted the same solution to my own application. I deal with templates that take function pointers as non-type template parameters. In the context of the question here, the workaround is `template struct value_to_type {}; template struct Resolve>> {...};` – Hossein Aug 13 '18 at 11:33
  • Nowadays you can use `std::bool_constant` from `` instead own `booltype` – maciek gajewski Dec 21 '20 at 11:26