Thread: Concepts and Parameter Packs

  1. #1
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445

    Concepts and Parameter Packs

    I'm developing a sort of pseudo-ORM system, and I'm having a little trouble getting part of it to work.

    I have a concept that looks like this:

    Code:
    template<typename T>
    concept bool DbColumnType()
    {
      return requires ()
      {
        std::is_base_of<DbColumnBase, T>::value;
      };
    }
    and then I have a class called Query, which has a function Select(), which looks like this:

    Code:
    template <DbColumnType... Args>
    QueryWithRowType<tableT, Args...> Select(const Args&... columns)
    {
      m_selectColumns.clear();
      SelectInternal(columns...);
      return QueryWithRowType<tableT, Args...>(*this);
    }
    QueryWithRowType is derived from Query.

    I'm getting errors from this code like the following:
    Code:
    In file included from include/tables.h:10:0,
                     from src/otherOrmTest.cpp:6:
    include/Query.h: In instantiation of ‘class Query<table1>’:
    src/otherOrmTest.cpp:12:26:   required from here
    include/Query.h:233:39: error: invalid use of pack expansion expression
         QueryWithRowType<tableT, Args...> Select(const Args&... columns)
                                           ^~~~~~
    And I'm just wondering if there is a correct syntax for using concepts with parameter packs, or if that scenario has been overlooked, thus far.

    Anyone have some insight?
    What can this strange device be?
    When I touch it, it gives forth a sound
    It's got wires that vibrate and give music
    What can this thing be that I found?

  2. #2
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Can't you only take an rvalue-reference to parameter packs? If you make sure to use std::forward, you preserve the const lvalue references that the caller would've fed in.

  3. #3
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    Anyone have some insight?
    O_o

    I wouldn't use concepts, but I will not bother you with all the details. I'll just say that we've seen another round "not ready for standardization" comments.

    *shrug*

    You have a few problems with your understanding of concepts. [Edit]Well, I'd say you at least have some problems with your understanding of concepts in their current state.[/Edit] I've provided a simple example that should work for you. (The example will not necessarily work depending on the version/branch of the compiler you are using.) You should compile with `VERSION` defined as 1, 2, 3, 4, and 5 to see an illustration of the different issues. I'm marked the interesting bits in the code. If you have further questions, you should expect to explain the importance behind the lines marked.

    Soma

    Code:
    #include <iostream>
    #include <type_traits>
    
    template
    <
         typename F
       , typename ... FArguments
    >
    struct is_integral_pack
    {
         constexpr static bool value = std::is_integral<F>::value && is_integral_pack<FArguments ...>::value;
    };
    
    template
    <
         typename F
    >
    struct is_integral_pack<F>
    {
         constexpr static bool value = std::is_integral<F>::value;
    };
    
    #if VERSION == 1
         template
         <
              typename F //! 1
         >
         concept bool MConcept()
         {
              return requires () //! 2
              {
                   is_integral_pack<F>::value;
              };
         }
    #elif VERSION == 2
         template
         <
              typename F //! 3
         >
         concept bool MConcept()
         {
              return is_integral_pack<F>::value; //! 4
         }
    #elif VERSION == 3
         template
         <
              typename ... F //! 5
         >
         concept bool MConcept()
         {
              return requires () //! 6
              {
                   is_integral_pack<F ...>::value;
              };
         }
    #else
         template
         <
              typename ... F //! 7
         >
         concept bool MConcept()
         {
              return is_integral_pack<F ...>::value; //! 8
         }
    #endif
    
    template
    <
         typename ... F
    >
    struct SResult
    {
    };
    
    template
    <
         typename F
    >
    struct SExample
    {
         template
         <
              MConcept ... Args
         >
         SResult<F, Args ...> doSomething
         (
              const Args & ... f
         )
         {
              std::cout << is_integral_pack<Args ...>::value << '\n';
         }
    };
    
    int main()
    {
         SExample<int> s;
         s.doSomething(0, 1);
    #if VERSION == 3 || VERSION == 4
              s.doSomething(0, 1, 0.0);
    #endif
         return(0);
    }
    Last edited by phantomotap; 06-17-2016 at 12:08 AM.
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  4. #4
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445
    Quote Originally Posted by phantomotap View Post
    I wouldn't use concepts, but I will not bother you with all the details.
    I'm actually interested in your reasons, if you'd care to share.

    Quote Originally Posted by phantomotap View Post
    I'll just say that we've seen another round "not ready for standardization" comments.
    I agree that it's not ready for production, but I am learning about it, and since it will eventually be part of the standard, I think it would be good to familiarize myself with it, even if it changes slightly from the current version. My code won't be used in any production systems until I'm satisfied that it's stable.

    Quote Originally Posted by phantomotap View Post
    You have a few problems with your understanding of concepts.
    Indeed. That's why I asked the question.

    Quote Originally Posted by phantomotap View Post
    I've provided a simple example that should work for you. (The example will not necessarily work depending on the version/branch of the compiler you are using.) You should compile with `VERSION` defined as 1, 2, 3, 4, and 5 to see an illustration of the different issues. I'm marked the interesting bits in the code. If you have further questions, you should expect to explain the importance behind the lines marked.
    I'm using GCC 6.1.1, on Ubuntu 12.04.

    Your example was very helpful. I understand now. The biggest part I was missing was that the concept needs to accept a parameter pack, and not just a single template parameter. The fact is that there just isn't very much information out there on the current state of concepts, and most of what I have seen simply reiterates all the same points. I've not seen a single article or tutorial that explains how to use them with parameter packs.

    I am very grateful for your assistance.
    What can this strange device be?
    When I touch it, it gives forth a sound
    It's got wires that vibrate and give music
    What can this thing be that I found?

  5. #5
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    I'm actually interested in your reasons, if you'd care to share.
    O_o

    One of my reasons:

    Code:
    template <typename F> concept bool MConcept = true;
    
    #if MEMBER == 1
    struct SExample
    {
    #endif
         template
         <
              MConcept ... Args
         >
         static int doSomething(){}
    #if MEMBER == 1
    };
    #endif
    
    #if MEMBER == 1
    #    define NS SExample
    #else
    #    define NS
    #endif
    
    int g = NS::doSomething<int>();
    The biggest part I was missing was that the concept needs to accept a parameter pack, and not just a single template parameter.
    The `MConcept ... Args` expression should expand as the `MConcept<Args[0]>, MConcept<Args[1]>, ..., MConcept<Args[n - 1]>, MConcept<Args[n]>` you apparently imagined.

    Maybe.

    Code:
    template <typename F> concept bool MConcept = true;
    
    struct SExample
    {
         template
         <
              MConcept ... Args
         >
         struct SNested
         {
              static int doSomething(){}
         };
    };
    
    int g = SExample::SNested<int>::doSomething();
    We have a technical paper introducing a mechanism with, in my opinion, either ambiguous examples or frustrating incompatibilities.

    I think it would be good to familiarize myself with it, even if it changes slightly from the current version.
    I don't think a reasonable person can properly familiarize oneself with tools that do not practicably exist.

    If you are really prepared for all the headbashing hoopjumpery, you can at least learn how best to apply concepts when they are finalized. You shouldn't necessarily plan on getting to use the same code. The syntax in some situations has changed some, and the semantics of some syntax is not entirely reasonable so will hopefully change.

    To share one other reason, we are going to see a lot of incompatible duplication without a lot of standard concepts and a standard mechanism for rolling existing traits into concepts. The committee is aware of the issue with politics and waiting on standardizing library extensions. We will either see concepts standardized followed by a strong concepts library in a later standard version, or we will see concepts delayed until a strong concepts library is prepared. I'm rather afraid we've already passed a point where politics will play too much of a role in a standard concepts library meaning history is going to repeat.

    The fact is that there just isn't very much information out there on the current state of concepts, and most of what I have seen simply reiterates all the same points.
    The final draft remains the best source for information.

    I've not seen a single article or tutorial that explains how to use them with parameter packs.
    I imagine the lack of instruction on the combination comes from the independent development of the mechanisms for such a long period.

    Soma
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. SDL Packs in Dev C++
    By Lesshardtofind in forum C++ Programming
    Replies: 2
    Last Post: 07-10-2009, 03:32 AM
  2. Replies: 6
    Last Post: 01-08-2008, 10:25 AM
  3. Visual Studio Service Packs
    By X PaYnE X in forum Windows Programming
    Replies: 4
    Last Post: 06-19-2005, 09:48 AM
  4. Microsoft & Service Packs & Internet
    By Witch_King in forum A Brief History of Cprogramming.com
    Replies: 10
    Last Post: 09-20-2001, 02:23 PM

Tags for this Thread