11

Is it possible to use typedef or using to declare a type alias inside a concept, as proposed by the Concepts TS? If I try something like the following MWE, the code does not compile (with gcc 6.2.1 and the -fconcepts switch)

#include <type_traits>

template<typename T>
concept bool TestConcept ()
{
    return requires(T t)
    {
        using V = T;
        std::is_integral<V>::value;
    };
}

int main()
{
    return 0;
}

Resulting error:

main.cpp: In function ‘concept bool TestConcept()’:
main.cpp:8:9:  error: expected primary-expression before ‘using’  
         using V = T;  
         ^~~~~   
main.cpp:8:9: error: expected ‘}’ before ‘using’
main.cpp:8:9: error: expected ‘;’ before ‘using’
main.cpp:4:14: error: definition of concept ‘concept bool TestConcept()’ has multiple  statements
 concept bool TestConcept ()  
              ^~~~~~~~~~~ 
main.cpp: At global scope:
main.cpp:11:1: error: expected declaration before ‘}’ token
 } 
 ^
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Slizzered
  • 869
  • 2
  • 9
  • 23
  • It seems like you'd want to use `typedef V T;`, which would would alias `T` to `V`. `using` is for invoking namespaces, or specific identifiers from a namespace. Here's an example: http://stackoverflow.com/questions/10103453/is-typedef-inside-of-a-function-body-a-bad-programming-practice – James Murphy Oct 30 '16 at 23:50
  • 2
    @JamesMurphy sorry, but since c++11 you can use the `using` keyword to express type aliases like you did before with `typedef`. Here is the reference: http://en.cppreference.com/w/cpp/language/type_alias. – erikzenker Oct 31 '16 at 10:07
  • @JamesMurphy the example also fails with the typedef, basically with the same error message. As erikzenker said, the syntax should be equivalent nowadays. – Slizzered Oct 31 '16 at 21:44
  • I haven't used enough C++11 to be aware of such nuances, but I figured I'd go looking for something on the topic. If the syntax is equivalent, then try using the `typedef` instead. – James Murphy Oct 31 '16 at 21:49

2 Answers2

4

No. According to the concepts TS, a requirement is:

requirement:
    simple-requirement
    type-requirement
    compound-requirement
    nested-requirement

Where a simple-requirement is an expression followed by a ; and a type-requirement is something like typename T::inner. The other two sound like what the name suggests.

A type alias is a declaration, not an expression, and so does not meet the requirement of a requirement.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • This feels unnecessarily restrictive to me. Do you know if there exists a reasonable workaround instead of writing the same complicated type over and over again? – Slizzered Nov 10 '16 at 09:47
4

This feels unnecessarily restrictive to me. Do you know if there exists a reasonable workaround instead of writing the same complicated type over and over again?

You can defer the implementation of the constraints to another concept, passing those types as template parameters:

template<typename Cont, typename It, typename Value>
concept bool InsertableWith = requires(Cont cont, It it, Value value) {
    // use It and Value as much as necessary
    cont.insert(it, std::move(value));
};

template<typename Cont>
concept bool Insertable = requires {
    // optional
    typename Cont::const_iterator;
    typename Cont::value_type;
} && InsertableWith<Cont, typename Cont::const_iterator, typename Cont::value_type>;

If you are considering doing that, I suggest you try it on simple examples before making a decision. How you write your concepts and constraints determines how a compiler will report errors, and of course having good errors is a big part of what makes concepts useful. Making it easier to write my concepts while making harder to understand errors is not a trade-off I would take lightly.

For instance that's why I redundantly added typename Cont::const_iterator; as an explicit constraint. This gives the compiler a chance to report this type requirement. I also was careful in picking InsertableWith as the name of the concept: I could have just easily have gone with detail::Insertable, but errors involving both Insertable and detail::Insertable could have been more confusing as a result.

Finally note that this all relies on the quality of implementation of the compiler, so I don't expect any approach to be definitive for the time being. I encourage playing with this Coliru demo.

Luc Danton
  • 34,649
  • 6
  • 70
  • 114