1

I'm writing a function for counting elements of multi dimensional vector

template<class T>
int real_size(const std::vector<T>& vec)
{
    int size=0;
    for(const auto& v : vec)
    {
        if(std::is_integral<T>::value ||
                std::is_floating_point<T>::value){
            size+=1;
        }
        else{
            size +=real_size(v);
        }
    }
    return size;
}

int main()
{
    std::vector<std::vector<int>> a(10);
    a[0]=std::vector<int>(10);
    std::cout<<real_size(a);
}

Which give me these errors :

 error: no matching function for call to 'real_size(const int&)'
             size +=real_size(v);
                           ^

That code seem's fine and error is irrelevant...the else statement should never become size +=real_size(int); because I'm checking the type of template parameter with std::is_integer .

But it seems that compiler fails to understand it at compile time !! Is it a compiler bug or I'm making a mistake ?

*I'm using gcc 4.8.1. g++ -std=c++11 *

uchar
  • 2,552
  • 4
  • 29
  • 50
  • 6
    Code in an `else` clause is not conditionally compiled. – chris Jun 12 '14 at 15:03
  • Have you overloaded `real_size()` because `v` is a `T` not a `std::vector` in the loop – 101010 Jun 12 '14 at 15:04
  • @40two I think compiler should understand that it's not necessary . – uchar Jun 12 '14 at 15:06
  • 2
    FYI: `std::is_arithmetic` – Brian Bi Jun 12 '14 at 15:06
  • 1
    @xyz no it won't. You are passing a `std::vector` as an input argument how is going to pass in the recursion call a T? – 101010 Jun 12 '14 at 15:08
  • @40two the type of T is define at compile time and It should understand that else statement never calls a template with int . which it seems does not . – uchar Jun 12 '14 at 15:11
  • Have you seen, @chris comment above? – 101010 Jun 12 '14 at 15:27
  • There were proposals (for C++11 IIRC) for a feature called static_if that could do what you expected from if, but it was rejected. – Fabio Fracassi Jun 12 '14 at 15:42
  • 1
    @FabioFracassi, I still think `static_if` makes code like this much easier to understand than tag dispatching, or SFINAE, or some other TMP method :/ I do see how it could be abused pretty easily, but if used right, it can make code shorter and keep things in one place. – chris Jun 12 '14 at 15:54
  • 3
    Related: http://stackoverflow.com/a/23982816/819272 – TemplateRex Jun 12 '14 at 17:16

3 Answers3

8

You can see how the compilation error makes some sort of sense if you replace the constants with their actual value. For int, that code is equivalent to the following:

    if(true || false){
        size+=1;
    }
    else{
        size +=real_size(v);
    }

Here the compiler would still complain that the else body is not valid: dead code must still be valid code.

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
4

The error is because the else branch still needs to be compiled. You can change this into two different functions and then using tag dispatching:

template<class T>
int real_size(const std::vector<T>& vec)
{
    int size=0;
    for(const auto& v : vec)
    {
        size += real_size_inner(std::is_arithmetic<T>(), v);
    }
    return size;
}

template<class T>
int real_size_inner(std::true_type, T&)
{
    return 1;
}

template<class T>
int real_size_inner(std::false_type, T& v)
{
    return real_size(v);
}

If you do some research into how std::advance is implemented in the standard, you will come to understand how this works, as it's implemented in the same way.

Simple
  • 13,992
  • 2
  • 47
  • 47
4

Conditional code is still compiled, and must be well-formed, even if it can be determined at compile time that it won't be executed.

One solution is to overload real_size for other types:

template <typename T>
typename std::enable_if<std::is_arithmetic<T>::value>::type
real_size(T const &) {
    return 1;
}

and reduce your loop to

for(const auto& v : vec) {
    size += real_size(v);
}
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • you mean something like this ? https://ideone.com/ef0Qcy , It give the wrong result ,result should be 20 not 10 – uchar Jun 12 '14 at 15:15
  • 1
    @xyz: By the logic of the (pseudo-)code you've posted, it should be 10: one `vector` of size 10 (giving 10) and 9 empty ones (each giving zero). – Mike Seymour Jun 12 '14 at 15:20