0

I am trying to create a concept to verify that a class has a specific method. The constraint should only check that a method with such name exist and for a specific return type. It should not put constraints on the arguments of the method. It can accept arbitrary number of arguments.

template< typename ExaminedType >
concept ConvertibleToStringObject = requires( ExaminedType instance )
{

    { instance.ToString( ... /* Accept arbitrary number of arguments */ ) } -> SameAs< std::string >;

};

Is it even possible?

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • 4
    No, it is not possible. But why do you need it? What is e.g. a function that wants a `ConvertibleToStringObject` going to do with it that requires _arbitrary_ number of arguments, rather than a specific number? Why can the concept not be templated on the types of arguments that should concretely be accepted? – user17732522 Mar 11 '23 at 19:48
  • I have many classes that support 'ToString'. Each has special things like what delimiter is needed in the time stamp - hour:minute:second or hour_minute_second. Do I want the string to be all upper case or lower case English letters. They all have default values, but again they have different options also. That is why I need it – rrrrTTTrrrr Mar 11 '23 at 19:51
  • 2
    I don't really understand. Are these options the arguments you want to give `instance.ToString`? If so, a user of `ConvertibleToStringObject` must know which possible options there are. There can only be predefined finite number of them. – user17732522 Mar 11 '23 at 19:55
  • I have a format class in the system. It only calls the method this way: instance.ToString() But in other places in the program for a specific class it can change: timeStamp.ToString( '_' ) title.ToString( true /* All letters upper case */ ) And there are much more variants – rrrrTTTrrrr Mar 11 '23 at 19:57
  • 2
    Absent any overloading, you could pick apart the type of `&ExaminedType::ToString` to verify that it exists, is a member function, and does return a string. Calling it, however, will require some more metaprogramming to examine the parameter list and decide what to pass in. – Quentin Mar 11 '23 at 19:57
  • @Quentin Yeah, wanted to try and avoid it. But I guess I will have to. Thanks!! – rrrrTTTrrrr Mar 11 '23 at 20:02
  • @rrrrTTTrrrr "_But in other places [...] for a specific class it can change_": The other places should then however not be using the same concept to constrain `timeStamp` as the first one does to constrain `instance`. They want different expressions relating to the type to be valid. I think what I mentioned in my first comment about making the argument types part of the template parameters for the concept (and which is demonstrated in the already posted answer) will work for that. Each specialization will be a _distinct_ concept and types may satisfy only _some_ of the specializations. – user17732522 Mar 11 '23 at 20:03
  • Adding to my previous comment: However, if there is a semantic meaning to these options like `'_'` representing a delimiter, then I think all of these concepts should be defined distinctly to make that clear, e.g. `ConvertibleToStringObject`, `ConvertibleToStringObjectWithDelimiter`, etc. You also have further problems, because e.g. a `char` is convertible to `bool`, so there is no way to differentiate between a `ToString` that accepts a delimiter and a boolean option as argument. It would be easier to use special types to represent these options which don't convert implicitly. – user17732522 Mar 11 '23 at 20:06
  • Does "arbitrary number of arguments" mean It is a variadic function template, or is it a C-style variadic function? – alagner Mar 11 '23 at 21:52

1 Answers1

1

Assuming the signature of ToString is std::string ToString(...):

template <class T>
concept HasToString = requires {
  { std::is_same_v<decltype (&T::ToString), auto(...) -> std::string> };
};

Live on Compiler Explorer

viraltaco_
  • 814
  • 5
  • 14
  • 1
    This only tests whether `T` has a non-type `ToString` member. Even after fixing it, it can only check that there exists exactly one variadic `ToString` member function. It doesn't work with templates, overloads, etc, but it shouldn't be relevant to the concept how `ToString`'s overload set is chosen. Also, OP wouldn't be using a variadic function for the use case they present in the comments (I hope). – user17732522 Mar 11 '23 at 22:14
  • I know. thus the first sentence in my answer. If the method has another signature it won't work. I know of no way to check the return type of a templated member function without instantiating it (eg: without specifying arguments). I don't believe that's possible, each template instance is a distinct function with its own signature. – viraltaco_ Mar 16 '23 at 02:02
  • Acknowledging the first sentence in your answer, the concept you've shown here is still just wrong. Ignoring the fact that [it simply doesn't work](https://godbolt.org/z/46Wddn9aK), just in principle: how would taking the address of a non-static member function ever yield a plain function type? – ildjarn Mar 20 '23 at 16:23
  • Yeah, you're right. It doesn't work. It does only checks if the member exists. It doesn't even have to be a function. – viraltaco_ Mar 25 '23 at 12:36