1

I have simplified the solution here to help me determine if a class has a member function:

template<typename T>
struct HasTest{
    template<typename R, typename S = decltype(declval<R>().test())> static true_type Test(R*);
    template<typename R> static false_type Test(...);
    using def = decltype(Test<T>(0));
};

I need to use HasTest<T>::def::value in the condition of a conditional_t. The problem is I have to do this with quite a number of functions, and since I need to declare a struct per function I was hoping to find a way to do the Substitution Fail Is Not An Error(SFINAE) within the condition. Something like:

conditional_t<struct { template<typename R, typename S = decltype(declval<R>().test())> static true_type Test(R*); template<typename R> static false_type Test(...); using def = decltype(Test<T>(0)); }::def, true_type, false_type>

That example clearly doesn't compile but hopefully it makes what I'm trying to do clear.

Right now I have to set up a struct for each method I plan to test for in namespace details and then use them in my conditional_t. This introduces pollution and separates the inner workings of the SFINAE from the conditional_ts it's used in.

Does C++14/17 provide me an alternative way to do this, or is there a way for me to declare and use an anonymous struct in the conditional_t condition?

I've created a simple test here that you're welcome to try things out on.

Community
  • 1
  • 1
Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • 2
    I can immediately say that anonymous struct can not be used there, since template arguments have to have external linkage. Not sure if 'other way' exists. – SergeyA May 06 '16 at 14:15
  • @SergeyA Yeah I've tried every workaround I can think of: Can't call a lambda, can't do template specialization locally, I'm asking here as a last resort cause my next stop is to dump everything in `namespace details` – Jonathan Mee May 06 '16 at 14:20
  • @SergeyA C++11 relaxed the rules, external linkage is no longer required. But your main point still stands, there are still restrictions that prevent an obvious answer to this question. –  May 06 '16 at 14:22
  • @hvd, yeah! I missed that. But as far as I can remember, anonymous structs has no linkage at all - and template arguments still have to have linkage. Am I right here? – SergeyA May 06 '16 at 14:26
  • @SergeyA Why would template arguments need linkage? Shouldn't they be established pre-linker? – Jonathan Mee May 06 '16 at 14:28
  • JonathanMee, I am trying to dig through the standard to find any support for my assumption :) I am not sure yet, may be @hvd will rescue me :) – SergeyA May 06 '16 at 14:29
  • 1
    http://wg21.cmeerw.net/cwg/issue62 – 101010 May 06 '16 at 14:30
  • 1
    @SergeyA I haven't digged through the standard, but `template void f(T) {} struct {} a; int main() { f(a); }` is rejected by GCC in C++03 mode, but compiles without any warnings in C++11 mode. I don't have a concrete reason to doubt GCC's judgement here. –  May 06 '16 at 14:30
  • @101010 I think the nail in the coffin was: "A type created by application of declarator operators to one of the types in this list" This means that there is no way to do this, unless C++17 has provided me a new construct. Thanks for the info. That would make a great answer. – Jonathan Mee May 06 '16 at 14:35
  • 1
    @hvd, right. C++11 tells us, than unnamed types now have the same linkage as if they had name. – SergeyA May 06 '16 at 14:37
  • Isn't [`is_detected`](http://en.cppreference.com/w/cpp/experimental/is_detected) what you search to shorten your code ? – Jarod42 May 06 '16 at 14:49
  • @Jarod42 I have to be honest I'm having a difficult time understanding the write up. It seems like it could be. In the [example code](http://ideone.com/G2U4B1) I just want to detect whether a class contains the `test` method. Could I use `is_detected` for that? – Jonathan Mee May 06 '16 at 14:58
  • @Jarod42 I got pretty excited there for a moment, but I don't think this is what I need. It seems to want a predefined specification of the function, like: `copy_assign_t`. It doen't seem to accept arbitrary functions. – Jonathan Mee May 06 '16 at 15:14
  • 1
    @JonathanMee: You may detect it like [that](http://coliru.stacked-crooked.com/a/8cd2199de0834e5f). – Jarod42 May 06 '16 at 15:31
  • @Jarod42 Yeah, [it looks like it's used to detect definitions](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4436.pdf) which is cool, but simply gives me a new problem. how could I create an anonymous definition such that I could contain it within a `conditional_t`? – Jonathan Mee May 06 '16 at 15:46
  • In fact you want a kind of `template auto foo(..) -> decltype(magic_disable_if(std::declval().test()), void())` to complement the enable form ? – Jarod42 May 06 '16 at 16:44
  • @Jarod42 I'm actually using the `conditional_t` within the body of a class to choose defines, based on multiple member functions. So I'm not sure who to manipulate what you're saying into being useful for type definitions. – Jonathan Mee May 06 '16 at 17:59

1 Answers1

0

According to the draft standard N4582 §14.1/p2 Template parameters [temp.param] (Emphasis Mine):

A storage class shall not be specified in a template-parameter declaration. Types shall not be defined in a template-parameter declaration.

Consequently, you can't have something like:

conditional_t<bool, struct Foo {...}>

And frankly I don't find a good reason to allow such constructs in C++, even more if they are unnamed classes (e.g., think of the mangling issues).

101010
  • 41,839
  • 11
  • 94
  • 168