2016-12-21 12 views
5

Я играю с понятиями. Вот минимальный пример, где я пытаюсь создать концепцию на основе сигнатур методов:Понятия: проверка подписи методов с аргументами

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"); 

К моему удивлению написания { a.bar(int) } -> int не работал, так что я прибегал к добавлению дополнительного аргумента к выражению requires. Это кажется немного странным, и мне было интересно, есть ли способ сделать то же самое. Еще одна вещь, которая работала, заключалась в использовании чего-то вроде { a.bar((int)0) } -> int, но я считаю это хуже.

ответ

6

Концепции проверки выражений, а a.bar(int) - это не одно. Написав

{ a.foo(int) } -> int 

вы попросить компилятор проверить, что вышеупомянутое выражение имеет тип int. Это не имеет смысла.

Вы нашли действительную альтернативу; другой может быть, так как тип a.bar(x) не зависит от x 'значения:

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"); 
3

Как фактическое значение типа не имеет значения, я предложил бы использовать int{} в качестве аргумента. Это документы цель аргумента несколько лучше, IMO:

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

Очевидно, что это не будет работать с типами, для которых не существует конструктор по умолчанию. В шаблонах, можно было бы использовать std::declval обойти подобную проблему, но здесь ошибки GCC:

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

Но нет ничего, чтобы остановить нас от написания эквивалента (но нереализованная) функции, которая будет использоваться с понятиями, например:

#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"); 
+0

Мне нравится, что вы makeval (), и я хотел бы увидеть его в стандарте. – YSC

Смежные вопросы