Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Concepts: checking signatures of methods with arguments

I've been playing around with concepts. Here's a minimal example where I'm trying to create a concept based on method signatures:

template<typename T>
concept bool myConcept() {
    return requires(T a, int i) {
        { a.foo()   } -> int;
        { a.bar(i)  } -> int;
    };
}

struct Object {
    int foo()    {return 0;}
    int bar(int) {return 0;}
};

static_assert(myConcept<Object>(), "Object does not adhere to myConcept");

To my surprise writing { a.bar(int) } -> int did not work, so I resorted to adding an additional argument to the requires expression. This seems a bit strange and I was wondering if there is a way to do the same thing. Another thing that worked was using something like { a.bar((int)0) } -> int, but I find this worse.

like image 430
ynimous Avatar asked Dec 21 '16 15:12

ynimous


People also ask

What is the signature of the method?

The signature of a method consists of the name of the method and the description (i.e., type, number, and position) of its parameters.

What does the signature of a method contain?

Method Signature According to Oracle, the method signature is comprised of the name and parameter types. Therefore, all the other elements of the method's declaration, such as modifiers, return type, parameter names, exception list, and body are not part of the signature.

What is the signature of a function in C++?

Function Signatures. A function signature consists of the function prototype. What it tells you is the general information about a function, its name, parameters, what scope it is in, and other miscellaneous information. C++ "mangle"s function names so that they are pretty, though in all truth they can be very ugly.

What is a signature in OOP?

In computer programming, especially object-oriented programming, a method is commonly identified by its unique method signature, which usually includes the method name, and the number, types and order of its parameters. A method signature is the smallest type of a method.


2 Answers

Concepts check expressions, and a.bar(int) is not one. By writing

{ a.foo(int) } -> int

you ask the compiler to check that the aforementioned expression has type int. Which doesn't make sense.

You did find a valid alternative; another one might be, since the type of a.bar(x) doesn't depend on x' value:

template<typename T>
concept bool myConcept() {
    return requires(T a) {
        { a.foo()   } -> int;
        { a.bar(0)  } -> int;
    };
}

struct Object {
    int foo()    {return 0;}
    int bar(int) {return 0;}
};

static_assert(myConcept<Object>(), "Object does not adhere to myConcept");
like image 53
YSC Avatar answered Nov 14 '22 23:11

YSC


As actual value of the type doesn't matter, I'd suggest using int{} as argument. This documents the purpose of the argument somewhat better, IMO:

{ a.bar(int{})  } -> int;

Obviously this won't work with types for which there is no default constructor. In templates, one would use std::declval to work around similar issue, but here GCC errors:

error: static assertion failed: declval() must not be used!

But there is nothing to stop us from writing equivalent (but unimplemented) function to be used with concepts, like this:

#include <type_traits>

template <class T>
typename std::add_rvalue_reference<T>::type makeval();

template<typename T>
concept bool myConcept() {
    return requires(T a, int i) {
        { a.foo() } -> int;
        { a.bar(makeval<int>()) } -> int;
    };
}

struct Object {
    int foo()    {return 0;}
    int bar(int) {return 0;}
};

static_assert(myConcept<Object>(), "Object does not adhere to myConcept");
like image 38
xaizek Avatar answered Nov 14 '22 23:11

xaizek