Try to make meta function which find method “size” in class












3














I am trying to write function getSize() which takes some template argument, tries to find method or field in this argument and return size() or size.



my code is:



#include <iostream>
#include <vector>
#include <utility>
#include <string>
#include <type_traits>


template <typename T>
class has_size {
private:
typedef char Yes;
typedef Yes No[2];

template <typename U, U> struct really_has;

template<typename C> static Yes& Test(really_has <size_t (C::*)() const, &C::size>*);
template<typename C> static Yes& Test(really_has <size_t (C::*)(), &C::size>*);

template<typename> static No& Test(...);

public:
static bool const value = sizeof(Test<T>(0)) == sizeof(Yes);
};

template <class T>
size_t get_size(T t){

size_t res = 0;
if(has_size<T>::value){

res = t.size();
}else{

res = t.size;
}


return res;

}

int main() {
std::vector<float> v(10);
std::cout << std::boolalpha << has_size<std::vector<float>>::value << std::endl;
std::cout << std::boolalpha << has_size<std::string>::value << std::endl;
size_t res = get_size(v);
std::cout<< res;
return 0;
}


The function has_size performs rightly in my example, but when I try to call getSize I got error:



prog.cpp: In function ‘int main()’:
prog.cpp:47:24: error: the value of ‘v’ is not usable in a constant expression
size_t res = get_size<v>;
^
prog.cpp:43:21: note: ‘v’ was not declared ‘constexpr’
std::vector<float> v(10);
^
prog.cpp:47:15: error: cannot resolve overloaded function ‘get_size’ based on conversion to type ‘size_t {aka long unsigned int}’
size_t res = get_size<v>;
^~~~~~~~~~~









share|improve this question
























  • Here you have example has_onEnter
    – Dawid Drozd
    Nov 16 '18 at 19:07








  • 1




    In your code probably you want to write get_size(v)
    – Dawid Drozd
    Nov 16 '18 at 19:09










  • Thanks! It is my bug...
    – Semyon
    Nov 18 '18 at 12:13
















3














I am trying to write function getSize() which takes some template argument, tries to find method or field in this argument and return size() or size.



my code is:



#include <iostream>
#include <vector>
#include <utility>
#include <string>
#include <type_traits>


template <typename T>
class has_size {
private:
typedef char Yes;
typedef Yes No[2];

template <typename U, U> struct really_has;

template<typename C> static Yes& Test(really_has <size_t (C::*)() const, &C::size>*);
template<typename C> static Yes& Test(really_has <size_t (C::*)(), &C::size>*);

template<typename> static No& Test(...);

public:
static bool const value = sizeof(Test<T>(0)) == sizeof(Yes);
};

template <class T>
size_t get_size(T t){

size_t res = 0;
if(has_size<T>::value){

res = t.size();
}else{

res = t.size;
}


return res;

}

int main() {
std::vector<float> v(10);
std::cout << std::boolalpha << has_size<std::vector<float>>::value << std::endl;
std::cout << std::boolalpha << has_size<std::string>::value << std::endl;
size_t res = get_size(v);
std::cout<< res;
return 0;
}


The function has_size performs rightly in my example, but when I try to call getSize I got error:



prog.cpp: In function ‘int main()’:
prog.cpp:47:24: error: the value of ‘v’ is not usable in a constant expression
size_t res = get_size<v>;
^
prog.cpp:43:21: note: ‘v’ was not declared ‘constexpr’
std::vector<float> v(10);
^
prog.cpp:47:15: error: cannot resolve overloaded function ‘get_size’ based on conversion to type ‘size_t {aka long unsigned int}’
size_t res = get_size<v>;
^~~~~~~~~~~









share|improve this question
























  • Here you have example has_onEnter
    – Dawid Drozd
    Nov 16 '18 at 19:07








  • 1




    In your code probably you want to write get_size(v)
    – Dawid Drozd
    Nov 16 '18 at 19:09










  • Thanks! It is my bug...
    – Semyon
    Nov 18 '18 at 12:13














3












3








3


1





I am trying to write function getSize() which takes some template argument, tries to find method or field in this argument and return size() or size.



my code is:



#include <iostream>
#include <vector>
#include <utility>
#include <string>
#include <type_traits>


template <typename T>
class has_size {
private:
typedef char Yes;
typedef Yes No[2];

template <typename U, U> struct really_has;

template<typename C> static Yes& Test(really_has <size_t (C::*)() const, &C::size>*);
template<typename C> static Yes& Test(really_has <size_t (C::*)(), &C::size>*);

template<typename> static No& Test(...);

public:
static bool const value = sizeof(Test<T>(0)) == sizeof(Yes);
};

template <class T>
size_t get_size(T t){

size_t res = 0;
if(has_size<T>::value){

res = t.size();
}else{

res = t.size;
}


return res;

}

int main() {
std::vector<float> v(10);
std::cout << std::boolalpha << has_size<std::vector<float>>::value << std::endl;
std::cout << std::boolalpha << has_size<std::string>::value << std::endl;
size_t res = get_size(v);
std::cout<< res;
return 0;
}


The function has_size performs rightly in my example, but when I try to call getSize I got error:



prog.cpp: In function ‘int main()’:
prog.cpp:47:24: error: the value of ‘v’ is not usable in a constant expression
size_t res = get_size<v>;
^
prog.cpp:43:21: note: ‘v’ was not declared ‘constexpr’
std::vector<float> v(10);
^
prog.cpp:47:15: error: cannot resolve overloaded function ‘get_size’ based on conversion to type ‘size_t {aka long unsigned int}’
size_t res = get_size<v>;
^~~~~~~~~~~









share|improve this question















I am trying to write function getSize() which takes some template argument, tries to find method or field in this argument and return size() or size.



my code is:



#include <iostream>
#include <vector>
#include <utility>
#include <string>
#include <type_traits>


template <typename T>
class has_size {
private:
typedef char Yes;
typedef Yes No[2];

template <typename U, U> struct really_has;

template<typename C> static Yes& Test(really_has <size_t (C::*)() const, &C::size>*);
template<typename C> static Yes& Test(really_has <size_t (C::*)(), &C::size>*);

template<typename> static No& Test(...);

public:
static bool const value = sizeof(Test<T>(0)) == sizeof(Yes);
};

template <class T>
size_t get_size(T t){

size_t res = 0;
if(has_size<T>::value){

res = t.size();
}else{

res = t.size;
}


return res;

}

int main() {
std::vector<float> v(10);
std::cout << std::boolalpha << has_size<std::vector<float>>::value << std::endl;
std::cout << std::boolalpha << has_size<std::string>::value << std::endl;
size_t res = get_size(v);
std::cout<< res;
return 0;
}


The function has_size performs rightly in my example, but when I try to call getSize I got error:



prog.cpp: In function ‘int main()’:
prog.cpp:47:24: error: the value of ‘v’ is not usable in a constant expression
size_t res = get_size<v>;
^
prog.cpp:43:21: note: ‘v’ was not declared ‘constexpr’
std::vector<float> v(10);
^
prog.cpp:47:15: error: cannot resolve overloaded function ‘get_size’ based on conversion to type ‘size_t {aka long unsigned int}’
size_t res = get_size<v>;
^~~~~~~~~~~






c++ c++11 template-meta-programming






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 18 '18 at 12:14

























asked Nov 16 '18 at 19:00









Semyon

184




184












  • Here you have example has_onEnter
    – Dawid Drozd
    Nov 16 '18 at 19:07








  • 1




    In your code probably you want to write get_size(v)
    – Dawid Drozd
    Nov 16 '18 at 19:09










  • Thanks! It is my bug...
    – Semyon
    Nov 18 '18 at 12:13


















  • Here you have example has_onEnter
    – Dawid Drozd
    Nov 16 '18 at 19:07








  • 1




    In your code probably you want to write get_size(v)
    – Dawid Drozd
    Nov 16 '18 at 19:09










  • Thanks! It is my bug...
    – Semyon
    Nov 18 '18 at 12:13
















Here you have example has_onEnter
– Dawid Drozd
Nov 16 '18 at 19:07






Here you have example has_onEnter
– Dawid Drozd
Nov 16 '18 at 19:07






1




1




In your code probably you want to write get_size(v)
– Dawid Drozd
Nov 16 '18 at 19:09




In your code probably you want to write get_size(v)
– Dawid Drozd
Nov 16 '18 at 19:09












Thanks! It is my bug...
– Semyon
Nov 18 '18 at 12:13




Thanks! It is my bug...
– Semyon
Nov 18 '18 at 12:13












3 Answers
3






active

oldest

votes


















3














So upgrading your code little bit: (for c++11)



struct MyStruct{
int size = 12;
};

// This function will compile only if has_size is true
template <class T,
typename std::enable_if<has_size<T>::value, int>::type = 0>
size_t get_size(const T& t){
return t.size();
}

// This function will compile only if has_size is FALSE (check negation !has_size)
template <class T,
typename std::enable_if<!has_size<T>::value, int>::type = 0>
size_t get_size(const T& t){
return t.size;
}

int main(){
std::vector<float> v(10);
std::cout << get_size(v) << std::endl;

MyStruct my;
std::cout << get_size(my) << std::endl;
return 0;
}


Documentation about std::enable_if



So I used case #4, enabled via a template parameter.



So each case of function of get_size will exist in final program depending on enable_if result. So compiler will ignore not meeting our conditions function to compile.





So upgrading your code little bit: (from c++17)



template <class T>
size_t get_size(const T& t){
size_t res = 0;
if constexpr(has_size<T>::value){
res = t.size();
}else{
res = t.size;
}
return res;
}

int main(){
std::vector<float> v(10);
std::cout<< get_size(v) << std::endl;
return 0;
}


So less code and more readable :)



This solution is using feature from C++17 if constexpr





Why your solution isn't working:



if(has_size<T>::value){ // <--- this is compile time result (has_size<T>::value) so always true or always false depends on template argument which is deduced from argument type
res = t.size(); // this need to compile always, so if it is vector then ok if something else that doesn't have such method will fail to compile
}else{
res = t.size; // this need to compile always, again as above
}


From smaller bugs/improvements:




  • pass by const& ;)


  • size_t res = get_size<v>; should be get_size(v) template argument will be deduced. But yeah you can write also get_size<std::vector>(v)






share|improve this answer































    2














    There's a lot going on here that needs to be fixed. To start, in your main size_t res = get_size<v>; isn't going to work, because you can't have v be a template argument, I'm assuming this was meant to be get_size(v) instead.



    In get_size you have this



    if (has_size<T>::value) {
    res = t.size();
    } else {
    res = t.size;
    }


    This isn't going to work because even though only one is used, the compiler sees you doing both t.size and t.size(). I see your question is tagged c++11 so I will provide a c++11 answer.



    First, I'm going to create some very simple classes to use, one with a member function and one with a data member



    // using distinc values 7 and 3 to differentiate easily later
    struct SizeData {
    std::size_t size = 7;
    };

    struct SizeFunc {
    std::size_t size() const { return 3; };
    };


    I'm going to also write a basic void_t for metaprogramming, and use a very standard modern metaprogramming approach to check if a given type has a .size() member function. (it looks like the technique you are attempting is outdated).



    template <typename>
    using void_type = void;

    template <typename T, typename = void>
    struct HasSizeFunc : std::false_type { };

    template <typename T>
    struct HasSizeFunc<T, void_type<decltype(std::declval<const T&>().size())>>
    : std::true_type { };


    I can use this very easily in a main to check whether something has a .size() or not



    int main() {
    std::cout << "SizeFunc: " << HasSizeFunc<SizeFunc>::value << 'n';
    std::cout << "SizeData: " << HasSizeFunc<SizeData>::value << 'n';
    }


    But now for the get_size() function. As I said earlier, your if/else won't work because both branches aren't compilable (if constexpr works but isn't available in c++11). So instead you can do what's called "tag dispatch" to decide which overload of a function to call in order to call the right .size



    // std::size_t may not be right for every type. leaving it for simplicity.
    template <typename T>
    std::size_t get_size_impl(T t, std::true_type) {
    return t.size();
    }
    template <typename T>
    std::size_t get_size_impl(T t, std::false_type) {
    return t.size;
    }

    template <typename T>
    std::size_t get_size(T t) { // note, this should probably be a const reference
    // second argument used to select an overload of get_size_impl
    return get_size_impl(t, HasSizeFunc<T>{});
    }


    And to use it:



    int main() {
    SizeFunc sf;
    std::cout << "SizeFunc: " << get_size(sf) << 'n';
    SizeData sd;
    std::cout << "SizeData: " << get_size(sd) << 'n';
    }


    click here to see all the code in one live example. I recommend watching these cppcon talks to learn more.



    Also, here is what I'd do in c++17






    share|improve this answer



















    • 1




      I like your solution but (my question) what if we have more cases ? I mean here you only assume .size() and .size how to handle 3+ case ? eg. .length ? We should use what kind of type ? Or maybe use extra template argument like get_size_impl<0>(t), get_size_impl<1>(t)... ?
      – Dawid Drozd
      Nov 20 '18 at 11:10






    • 1




      @DawidDrozd tag dispatch still works, but you need more than two tags here is an expanded example of the c++11 version. This approach is used by the standard library with different iterators for example, inside something like std::distance
      – Ryan Haining
      Nov 20 '18 at 17:05






    • 1




      @DawidDrozd also to switch it up for c++17 you can do a similar thing with integral_constant and if constexpr, live example here
      – Ryan Haining
      Nov 21 '18 at 17:51



















    1














    if(has_size<T>::value){
    res = t.size();
    }else{
    res = t.size;
    }


    these branches are evaluated at runtime. So both branches must be valid at compile time.



    #define RETURNS(...) 
    noexcept(noexcept(__VA_ARGS__))
    -> decltype(__VA_ARGS__)
    { return __VA_ARGS__; }


    template<class S, class...Ts>
    auto select( S, Ts&&...ts )
    RETURNS( std::get<S::value>(std::forward_as_tuple( std::forward<Ts>(ts)... )) )


    which gives you a compile-time branch.



    struct call_size_t {
    template<class T>
    auto operator()( T&& t ) const
    RETURNS( t.size() )
    };
    struct get_size_t {
    template<class T>
    auto operator()( T&& t ) const
    RETURNS( t.size )
    };

    auto f = select(has_size<T>{},
    get_size_t{},
    call_size_t{}
    };
    res = f(t);


    this is quite annoying because you are in c++11; code is less than half this in c++14 and becomes trivial in c++17.






    share|improve this answer





















      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53343884%2ftry-to-make-meta-function-which-find-method-size-in-class%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      3














      So upgrading your code little bit: (for c++11)



      struct MyStruct{
      int size = 12;
      };

      // This function will compile only if has_size is true
      template <class T,
      typename std::enable_if<has_size<T>::value, int>::type = 0>
      size_t get_size(const T& t){
      return t.size();
      }

      // This function will compile only if has_size is FALSE (check negation !has_size)
      template <class T,
      typename std::enable_if<!has_size<T>::value, int>::type = 0>
      size_t get_size(const T& t){
      return t.size;
      }

      int main(){
      std::vector<float> v(10);
      std::cout << get_size(v) << std::endl;

      MyStruct my;
      std::cout << get_size(my) << std::endl;
      return 0;
      }


      Documentation about std::enable_if



      So I used case #4, enabled via a template parameter.



      So each case of function of get_size will exist in final program depending on enable_if result. So compiler will ignore not meeting our conditions function to compile.





      So upgrading your code little bit: (from c++17)



      template <class T>
      size_t get_size(const T& t){
      size_t res = 0;
      if constexpr(has_size<T>::value){
      res = t.size();
      }else{
      res = t.size;
      }
      return res;
      }

      int main(){
      std::vector<float> v(10);
      std::cout<< get_size(v) << std::endl;
      return 0;
      }


      So less code and more readable :)



      This solution is using feature from C++17 if constexpr





      Why your solution isn't working:



      if(has_size<T>::value){ // <--- this is compile time result (has_size<T>::value) so always true or always false depends on template argument which is deduced from argument type
      res = t.size(); // this need to compile always, so if it is vector then ok if something else that doesn't have such method will fail to compile
      }else{
      res = t.size; // this need to compile always, again as above
      }


      From smaller bugs/improvements:




      • pass by const& ;)


      • size_t res = get_size<v>; should be get_size(v) template argument will be deduced. But yeah you can write also get_size<std::vector>(v)






      share|improve this answer




























        3














        So upgrading your code little bit: (for c++11)



        struct MyStruct{
        int size = 12;
        };

        // This function will compile only if has_size is true
        template <class T,
        typename std::enable_if<has_size<T>::value, int>::type = 0>
        size_t get_size(const T& t){
        return t.size();
        }

        // This function will compile only if has_size is FALSE (check negation !has_size)
        template <class T,
        typename std::enable_if<!has_size<T>::value, int>::type = 0>
        size_t get_size(const T& t){
        return t.size;
        }

        int main(){
        std::vector<float> v(10);
        std::cout << get_size(v) << std::endl;

        MyStruct my;
        std::cout << get_size(my) << std::endl;
        return 0;
        }


        Documentation about std::enable_if



        So I used case #4, enabled via a template parameter.



        So each case of function of get_size will exist in final program depending on enable_if result. So compiler will ignore not meeting our conditions function to compile.





        So upgrading your code little bit: (from c++17)



        template <class T>
        size_t get_size(const T& t){
        size_t res = 0;
        if constexpr(has_size<T>::value){
        res = t.size();
        }else{
        res = t.size;
        }
        return res;
        }

        int main(){
        std::vector<float> v(10);
        std::cout<< get_size(v) << std::endl;
        return 0;
        }


        So less code and more readable :)



        This solution is using feature from C++17 if constexpr





        Why your solution isn't working:



        if(has_size<T>::value){ // <--- this is compile time result (has_size<T>::value) so always true or always false depends on template argument which is deduced from argument type
        res = t.size(); // this need to compile always, so if it is vector then ok if something else that doesn't have such method will fail to compile
        }else{
        res = t.size; // this need to compile always, again as above
        }


        From smaller bugs/improvements:




        • pass by const& ;)


        • size_t res = get_size<v>; should be get_size(v) template argument will be deduced. But yeah you can write also get_size<std::vector>(v)






        share|improve this answer


























          3












          3








          3






          So upgrading your code little bit: (for c++11)



          struct MyStruct{
          int size = 12;
          };

          // This function will compile only if has_size is true
          template <class T,
          typename std::enable_if<has_size<T>::value, int>::type = 0>
          size_t get_size(const T& t){
          return t.size();
          }

          // This function will compile only if has_size is FALSE (check negation !has_size)
          template <class T,
          typename std::enable_if<!has_size<T>::value, int>::type = 0>
          size_t get_size(const T& t){
          return t.size;
          }

          int main(){
          std::vector<float> v(10);
          std::cout << get_size(v) << std::endl;

          MyStruct my;
          std::cout << get_size(my) << std::endl;
          return 0;
          }


          Documentation about std::enable_if



          So I used case #4, enabled via a template parameter.



          So each case of function of get_size will exist in final program depending on enable_if result. So compiler will ignore not meeting our conditions function to compile.





          So upgrading your code little bit: (from c++17)



          template <class T>
          size_t get_size(const T& t){
          size_t res = 0;
          if constexpr(has_size<T>::value){
          res = t.size();
          }else{
          res = t.size;
          }
          return res;
          }

          int main(){
          std::vector<float> v(10);
          std::cout<< get_size(v) << std::endl;
          return 0;
          }


          So less code and more readable :)



          This solution is using feature from C++17 if constexpr





          Why your solution isn't working:



          if(has_size<T>::value){ // <--- this is compile time result (has_size<T>::value) so always true or always false depends on template argument which is deduced from argument type
          res = t.size(); // this need to compile always, so if it is vector then ok if something else that doesn't have such method will fail to compile
          }else{
          res = t.size; // this need to compile always, again as above
          }


          From smaller bugs/improvements:




          • pass by const& ;)


          • size_t res = get_size<v>; should be get_size(v) template argument will be deduced. But yeah you can write also get_size<std::vector>(v)






          share|improve this answer














          So upgrading your code little bit: (for c++11)



          struct MyStruct{
          int size = 12;
          };

          // This function will compile only if has_size is true
          template <class T,
          typename std::enable_if<has_size<T>::value, int>::type = 0>
          size_t get_size(const T& t){
          return t.size();
          }

          // This function will compile only if has_size is FALSE (check negation !has_size)
          template <class T,
          typename std::enable_if<!has_size<T>::value, int>::type = 0>
          size_t get_size(const T& t){
          return t.size;
          }

          int main(){
          std::vector<float> v(10);
          std::cout << get_size(v) << std::endl;

          MyStruct my;
          std::cout << get_size(my) << std::endl;
          return 0;
          }


          Documentation about std::enable_if



          So I used case #4, enabled via a template parameter.



          So each case of function of get_size will exist in final program depending on enable_if result. So compiler will ignore not meeting our conditions function to compile.





          So upgrading your code little bit: (from c++17)



          template <class T>
          size_t get_size(const T& t){
          size_t res = 0;
          if constexpr(has_size<T>::value){
          res = t.size();
          }else{
          res = t.size;
          }
          return res;
          }

          int main(){
          std::vector<float> v(10);
          std::cout<< get_size(v) << std::endl;
          return 0;
          }


          So less code and more readable :)



          This solution is using feature from C++17 if constexpr





          Why your solution isn't working:



          if(has_size<T>::value){ // <--- this is compile time result (has_size<T>::value) so always true or always false depends on template argument which is deduced from argument type
          res = t.size(); // this need to compile always, so if it is vector then ok if something else that doesn't have such method will fail to compile
          }else{
          res = t.size; // this need to compile always, again as above
          }


          From smaller bugs/improvements:




          • pass by const& ;)


          • size_t res = get_size<v>; should be get_size(v) template argument will be deduced. But yeah you can write also get_size<std::vector>(v)







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 16 '18 at 19:46

























          answered Nov 16 '18 at 19:19









          Dawid Drozd

          7,93544152




          7,93544152

























              2














              There's a lot going on here that needs to be fixed. To start, in your main size_t res = get_size<v>; isn't going to work, because you can't have v be a template argument, I'm assuming this was meant to be get_size(v) instead.



              In get_size you have this



              if (has_size<T>::value) {
              res = t.size();
              } else {
              res = t.size;
              }


              This isn't going to work because even though only one is used, the compiler sees you doing both t.size and t.size(). I see your question is tagged c++11 so I will provide a c++11 answer.



              First, I'm going to create some very simple classes to use, one with a member function and one with a data member



              // using distinc values 7 and 3 to differentiate easily later
              struct SizeData {
              std::size_t size = 7;
              };

              struct SizeFunc {
              std::size_t size() const { return 3; };
              };


              I'm going to also write a basic void_t for metaprogramming, and use a very standard modern metaprogramming approach to check if a given type has a .size() member function. (it looks like the technique you are attempting is outdated).



              template <typename>
              using void_type = void;

              template <typename T, typename = void>
              struct HasSizeFunc : std::false_type { };

              template <typename T>
              struct HasSizeFunc<T, void_type<decltype(std::declval<const T&>().size())>>
              : std::true_type { };


              I can use this very easily in a main to check whether something has a .size() or not



              int main() {
              std::cout << "SizeFunc: " << HasSizeFunc<SizeFunc>::value << 'n';
              std::cout << "SizeData: " << HasSizeFunc<SizeData>::value << 'n';
              }


              But now for the get_size() function. As I said earlier, your if/else won't work because both branches aren't compilable (if constexpr works but isn't available in c++11). So instead you can do what's called "tag dispatch" to decide which overload of a function to call in order to call the right .size



              // std::size_t may not be right for every type. leaving it for simplicity.
              template <typename T>
              std::size_t get_size_impl(T t, std::true_type) {
              return t.size();
              }
              template <typename T>
              std::size_t get_size_impl(T t, std::false_type) {
              return t.size;
              }

              template <typename T>
              std::size_t get_size(T t) { // note, this should probably be a const reference
              // second argument used to select an overload of get_size_impl
              return get_size_impl(t, HasSizeFunc<T>{});
              }


              And to use it:



              int main() {
              SizeFunc sf;
              std::cout << "SizeFunc: " << get_size(sf) << 'n';
              SizeData sd;
              std::cout << "SizeData: " << get_size(sd) << 'n';
              }


              click here to see all the code in one live example. I recommend watching these cppcon talks to learn more.



              Also, here is what I'd do in c++17






              share|improve this answer



















              • 1




                I like your solution but (my question) what if we have more cases ? I mean here you only assume .size() and .size how to handle 3+ case ? eg. .length ? We should use what kind of type ? Or maybe use extra template argument like get_size_impl<0>(t), get_size_impl<1>(t)... ?
                – Dawid Drozd
                Nov 20 '18 at 11:10






              • 1




                @DawidDrozd tag dispatch still works, but you need more than two tags here is an expanded example of the c++11 version. This approach is used by the standard library with different iterators for example, inside something like std::distance
                – Ryan Haining
                Nov 20 '18 at 17:05






              • 1




                @DawidDrozd also to switch it up for c++17 you can do a similar thing with integral_constant and if constexpr, live example here
                – Ryan Haining
                Nov 21 '18 at 17:51
















              2














              There's a lot going on here that needs to be fixed. To start, in your main size_t res = get_size<v>; isn't going to work, because you can't have v be a template argument, I'm assuming this was meant to be get_size(v) instead.



              In get_size you have this



              if (has_size<T>::value) {
              res = t.size();
              } else {
              res = t.size;
              }


              This isn't going to work because even though only one is used, the compiler sees you doing both t.size and t.size(). I see your question is tagged c++11 so I will provide a c++11 answer.



              First, I'm going to create some very simple classes to use, one with a member function and one with a data member



              // using distinc values 7 and 3 to differentiate easily later
              struct SizeData {
              std::size_t size = 7;
              };

              struct SizeFunc {
              std::size_t size() const { return 3; };
              };


              I'm going to also write a basic void_t for metaprogramming, and use a very standard modern metaprogramming approach to check if a given type has a .size() member function. (it looks like the technique you are attempting is outdated).



              template <typename>
              using void_type = void;

              template <typename T, typename = void>
              struct HasSizeFunc : std::false_type { };

              template <typename T>
              struct HasSizeFunc<T, void_type<decltype(std::declval<const T&>().size())>>
              : std::true_type { };


              I can use this very easily in a main to check whether something has a .size() or not



              int main() {
              std::cout << "SizeFunc: " << HasSizeFunc<SizeFunc>::value << 'n';
              std::cout << "SizeData: " << HasSizeFunc<SizeData>::value << 'n';
              }


              But now for the get_size() function. As I said earlier, your if/else won't work because both branches aren't compilable (if constexpr works but isn't available in c++11). So instead you can do what's called "tag dispatch" to decide which overload of a function to call in order to call the right .size



              // std::size_t may not be right for every type. leaving it for simplicity.
              template <typename T>
              std::size_t get_size_impl(T t, std::true_type) {
              return t.size();
              }
              template <typename T>
              std::size_t get_size_impl(T t, std::false_type) {
              return t.size;
              }

              template <typename T>
              std::size_t get_size(T t) { // note, this should probably be a const reference
              // second argument used to select an overload of get_size_impl
              return get_size_impl(t, HasSizeFunc<T>{});
              }


              And to use it:



              int main() {
              SizeFunc sf;
              std::cout << "SizeFunc: " << get_size(sf) << 'n';
              SizeData sd;
              std::cout << "SizeData: " << get_size(sd) << 'n';
              }


              click here to see all the code in one live example. I recommend watching these cppcon talks to learn more.



              Also, here is what I'd do in c++17






              share|improve this answer



















              • 1




                I like your solution but (my question) what if we have more cases ? I mean here you only assume .size() and .size how to handle 3+ case ? eg. .length ? We should use what kind of type ? Or maybe use extra template argument like get_size_impl<0>(t), get_size_impl<1>(t)... ?
                – Dawid Drozd
                Nov 20 '18 at 11:10






              • 1




                @DawidDrozd tag dispatch still works, but you need more than two tags here is an expanded example of the c++11 version. This approach is used by the standard library with different iterators for example, inside something like std::distance
                – Ryan Haining
                Nov 20 '18 at 17:05






              • 1




                @DawidDrozd also to switch it up for c++17 you can do a similar thing with integral_constant and if constexpr, live example here
                – Ryan Haining
                Nov 21 '18 at 17:51














              2












              2








              2






              There's a lot going on here that needs to be fixed. To start, in your main size_t res = get_size<v>; isn't going to work, because you can't have v be a template argument, I'm assuming this was meant to be get_size(v) instead.



              In get_size you have this



              if (has_size<T>::value) {
              res = t.size();
              } else {
              res = t.size;
              }


              This isn't going to work because even though only one is used, the compiler sees you doing both t.size and t.size(). I see your question is tagged c++11 so I will provide a c++11 answer.



              First, I'm going to create some very simple classes to use, one with a member function and one with a data member



              // using distinc values 7 and 3 to differentiate easily later
              struct SizeData {
              std::size_t size = 7;
              };

              struct SizeFunc {
              std::size_t size() const { return 3; };
              };


              I'm going to also write a basic void_t for metaprogramming, and use a very standard modern metaprogramming approach to check if a given type has a .size() member function. (it looks like the technique you are attempting is outdated).



              template <typename>
              using void_type = void;

              template <typename T, typename = void>
              struct HasSizeFunc : std::false_type { };

              template <typename T>
              struct HasSizeFunc<T, void_type<decltype(std::declval<const T&>().size())>>
              : std::true_type { };


              I can use this very easily in a main to check whether something has a .size() or not



              int main() {
              std::cout << "SizeFunc: " << HasSizeFunc<SizeFunc>::value << 'n';
              std::cout << "SizeData: " << HasSizeFunc<SizeData>::value << 'n';
              }


              But now for the get_size() function. As I said earlier, your if/else won't work because both branches aren't compilable (if constexpr works but isn't available in c++11). So instead you can do what's called "tag dispatch" to decide which overload of a function to call in order to call the right .size



              // std::size_t may not be right for every type. leaving it for simplicity.
              template <typename T>
              std::size_t get_size_impl(T t, std::true_type) {
              return t.size();
              }
              template <typename T>
              std::size_t get_size_impl(T t, std::false_type) {
              return t.size;
              }

              template <typename T>
              std::size_t get_size(T t) { // note, this should probably be a const reference
              // second argument used to select an overload of get_size_impl
              return get_size_impl(t, HasSizeFunc<T>{});
              }


              And to use it:



              int main() {
              SizeFunc sf;
              std::cout << "SizeFunc: " << get_size(sf) << 'n';
              SizeData sd;
              std::cout << "SizeData: " << get_size(sd) << 'n';
              }


              click here to see all the code in one live example. I recommend watching these cppcon talks to learn more.



              Also, here is what I'd do in c++17






              share|improve this answer














              There's a lot going on here that needs to be fixed. To start, in your main size_t res = get_size<v>; isn't going to work, because you can't have v be a template argument, I'm assuming this was meant to be get_size(v) instead.



              In get_size you have this



              if (has_size<T>::value) {
              res = t.size();
              } else {
              res = t.size;
              }


              This isn't going to work because even though only one is used, the compiler sees you doing both t.size and t.size(). I see your question is tagged c++11 so I will provide a c++11 answer.



              First, I'm going to create some very simple classes to use, one with a member function and one with a data member



              // using distinc values 7 and 3 to differentiate easily later
              struct SizeData {
              std::size_t size = 7;
              };

              struct SizeFunc {
              std::size_t size() const { return 3; };
              };


              I'm going to also write a basic void_t for metaprogramming, and use a very standard modern metaprogramming approach to check if a given type has a .size() member function. (it looks like the technique you are attempting is outdated).



              template <typename>
              using void_type = void;

              template <typename T, typename = void>
              struct HasSizeFunc : std::false_type { };

              template <typename T>
              struct HasSizeFunc<T, void_type<decltype(std::declval<const T&>().size())>>
              : std::true_type { };


              I can use this very easily in a main to check whether something has a .size() or not



              int main() {
              std::cout << "SizeFunc: " << HasSizeFunc<SizeFunc>::value << 'n';
              std::cout << "SizeData: " << HasSizeFunc<SizeData>::value << 'n';
              }


              But now for the get_size() function. As I said earlier, your if/else won't work because both branches aren't compilable (if constexpr works but isn't available in c++11). So instead you can do what's called "tag dispatch" to decide which overload of a function to call in order to call the right .size



              // std::size_t may not be right for every type. leaving it for simplicity.
              template <typename T>
              std::size_t get_size_impl(T t, std::true_type) {
              return t.size();
              }
              template <typename T>
              std::size_t get_size_impl(T t, std::false_type) {
              return t.size;
              }

              template <typename T>
              std::size_t get_size(T t) { // note, this should probably be a const reference
              // second argument used to select an overload of get_size_impl
              return get_size_impl(t, HasSizeFunc<T>{});
              }


              And to use it:



              int main() {
              SizeFunc sf;
              std::cout << "SizeFunc: " << get_size(sf) << 'n';
              SizeData sd;
              std::cout << "SizeData: " << get_size(sd) << 'n';
              }


              click here to see all the code in one live example. I recommend watching these cppcon talks to learn more.



              Also, here is what I'd do in c++17







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Nov 16 '18 at 19:30

























              answered Nov 16 '18 at 19:23









              Ryan Haining

              21.2k869121




              21.2k869121








              • 1




                I like your solution but (my question) what if we have more cases ? I mean here you only assume .size() and .size how to handle 3+ case ? eg. .length ? We should use what kind of type ? Or maybe use extra template argument like get_size_impl<0>(t), get_size_impl<1>(t)... ?
                – Dawid Drozd
                Nov 20 '18 at 11:10






              • 1




                @DawidDrozd tag dispatch still works, but you need more than two tags here is an expanded example of the c++11 version. This approach is used by the standard library with different iterators for example, inside something like std::distance
                – Ryan Haining
                Nov 20 '18 at 17:05






              • 1




                @DawidDrozd also to switch it up for c++17 you can do a similar thing with integral_constant and if constexpr, live example here
                – Ryan Haining
                Nov 21 '18 at 17:51














              • 1




                I like your solution but (my question) what if we have more cases ? I mean here you only assume .size() and .size how to handle 3+ case ? eg. .length ? We should use what kind of type ? Or maybe use extra template argument like get_size_impl<0>(t), get_size_impl<1>(t)... ?
                – Dawid Drozd
                Nov 20 '18 at 11:10






              • 1




                @DawidDrozd tag dispatch still works, but you need more than two tags here is an expanded example of the c++11 version. This approach is used by the standard library with different iterators for example, inside something like std::distance
                – Ryan Haining
                Nov 20 '18 at 17:05






              • 1




                @DawidDrozd also to switch it up for c++17 you can do a similar thing with integral_constant and if constexpr, live example here
                – Ryan Haining
                Nov 21 '18 at 17:51








              1




              1




              I like your solution but (my question) what if we have more cases ? I mean here you only assume .size() and .size how to handle 3+ case ? eg. .length ? We should use what kind of type ? Or maybe use extra template argument like get_size_impl<0>(t), get_size_impl<1>(t)... ?
              – Dawid Drozd
              Nov 20 '18 at 11:10




              I like your solution but (my question) what if we have more cases ? I mean here you only assume .size() and .size how to handle 3+ case ? eg. .length ? We should use what kind of type ? Or maybe use extra template argument like get_size_impl<0>(t), get_size_impl<1>(t)... ?
              – Dawid Drozd
              Nov 20 '18 at 11:10




              1




              1




              @DawidDrozd tag dispatch still works, but you need more than two tags here is an expanded example of the c++11 version. This approach is used by the standard library with different iterators for example, inside something like std::distance
              – Ryan Haining
              Nov 20 '18 at 17:05




              @DawidDrozd tag dispatch still works, but you need more than two tags here is an expanded example of the c++11 version. This approach is used by the standard library with different iterators for example, inside something like std::distance
              – Ryan Haining
              Nov 20 '18 at 17:05




              1




              1




              @DawidDrozd also to switch it up for c++17 you can do a similar thing with integral_constant and if constexpr, live example here
              – Ryan Haining
              Nov 21 '18 at 17:51




              @DawidDrozd also to switch it up for c++17 you can do a similar thing with integral_constant and if constexpr, live example here
              – Ryan Haining
              Nov 21 '18 at 17:51











              1














              if(has_size<T>::value){
              res = t.size();
              }else{
              res = t.size;
              }


              these branches are evaluated at runtime. So both branches must be valid at compile time.



              #define RETURNS(...) 
              noexcept(noexcept(__VA_ARGS__))
              -> decltype(__VA_ARGS__)
              { return __VA_ARGS__; }


              template<class S, class...Ts>
              auto select( S, Ts&&...ts )
              RETURNS( std::get<S::value>(std::forward_as_tuple( std::forward<Ts>(ts)... )) )


              which gives you a compile-time branch.



              struct call_size_t {
              template<class T>
              auto operator()( T&& t ) const
              RETURNS( t.size() )
              };
              struct get_size_t {
              template<class T>
              auto operator()( T&& t ) const
              RETURNS( t.size )
              };

              auto f = select(has_size<T>{},
              get_size_t{},
              call_size_t{}
              };
              res = f(t);


              this is quite annoying because you are in c++11; code is less than half this in c++14 and becomes trivial in c++17.






              share|improve this answer


























                1














                if(has_size<T>::value){
                res = t.size();
                }else{
                res = t.size;
                }


                these branches are evaluated at runtime. So both branches must be valid at compile time.



                #define RETURNS(...) 
                noexcept(noexcept(__VA_ARGS__))
                -> decltype(__VA_ARGS__)
                { return __VA_ARGS__; }


                template<class S, class...Ts>
                auto select( S, Ts&&...ts )
                RETURNS( std::get<S::value>(std::forward_as_tuple( std::forward<Ts>(ts)... )) )


                which gives you a compile-time branch.



                struct call_size_t {
                template<class T>
                auto operator()( T&& t ) const
                RETURNS( t.size() )
                };
                struct get_size_t {
                template<class T>
                auto operator()( T&& t ) const
                RETURNS( t.size )
                };

                auto f = select(has_size<T>{},
                get_size_t{},
                call_size_t{}
                };
                res = f(t);


                this is quite annoying because you are in c++11; code is less than half this in c++14 and becomes trivial in c++17.






                share|improve this answer
























                  1












                  1








                  1






                  if(has_size<T>::value){
                  res = t.size();
                  }else{
                  res = t.size;
                  }


                  these branches are evaluated at runtime. So both branches must be valid at compile time.



                  #define RETURNS(...) 
                  noexcept(noexcept(__VA_ARGS__))
                  -> decltype(__VA_ARGS__)
                  { return __VA_ARGS__; }


                  template<class S, class...Ts>
                  auto select( S, Ts&&...ts )
                  RETURNS( std::get<S::value>(std::forward_as_tuple( std::forward<Ts>(ts)... )) )


                  which gives you a compile-time branch.



                  struct call_size_t {
                  template<class T>
                  auto operator()( T&& t ) const
                  RETURNS( t.size() )
                  };
                  struct get_size_t {
                  template<class T>
                  auto operator()( T&& t ) const
                  RETURNS( t.size )
                  };

                  auto f = select(has_size<T>{},
                  get_size_t{},
                  call_size_t{}
                  };
                  res = f(t);


                  this is quite annoying because you are in c++11; code is less than half this in c++14 and becomes trivial in c++17.






                  share|improve this answer












                  if(has_size<T>::value){
                  res = t.size();
                  }else{
                  res = t.size;
                  }


                  these branches are evaluated at runtime. So both branches must be valid at compile time.



                  #define RETURNS(...) 
                  noexcept(noexcept(__VA_ARGS__))
                  -> decltype(__VA_ARGS__)
                  { return __VA_ARGS__; }


                  template<class S, class...Ts>
                  auto select( S, Ts&&...ts )
                  RETURNS( std::get<S::value>(std::forward_as_tuple( std::forward<Ts>(ts)... )) )


                  which gives you a compile-time branch.



                  struct call_size_t {
                  template<class T>
                  auto operator()( T&& t ) const
                  RETURNS( t.size() )
                  };
                  struct get_size_t {
                  template<class T>
                  auto operator()( T&& t ) const
                  RETURNS( t.size )
                  };

                  auto f = select(has_size<T>{},
                  get_size_t{},
                  call_size_t{}
                  };
                  res = f(t);


                  this is quite annoying because you are in c++11; code is less than half this in c++14 and becomes trivial in c++17.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 16 '18 at 19:19









                  Yakk - Adam Nevraumont

                  182k19188374




                  182k19188374






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.





                      Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                      Please pay close attention to the following guidance:


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53343884%2ftry-to-make-meta-function-which-find-method-size-in-class%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Biblatex bibliography style without URLs when DOI exists (in Overleaf with Zotero bibliography)

                      ComboBox Display Member on multiple fields

                      Is it possible to collect Nectar points via Trainline?