Home > Software design >  c : do we need to explicitly specify type info for template function, when using NULL/nullptr?
c : do we need to explicitly specify type info for template function, when using NULL/nullptr?

Time:08-29

I've got this template function:

template<typename T>
void f(const T* t1, const T* t2) {}

Then in main():

    int i = 1;
    f(&i, NULL);

It doesn't compile, saying candidate template ignored: could not match 'const T *' against 'int'

If change it into:

    int i = 1;
    f(&i, nullptr); // same error!

I know I can fix it like this, specifying the type info:

    int i = 1;
    f<int>(&i, NULL);

Ok, it gets compiled.

But isn't it that, c compiler could do type deduction for us : so that we can call template functions without specifying all the type information?

Seems NULL/nullptr here is an unusual case for template.

My question: is there a way to go without f<int> in each place, just f, when there's NULL/nullptr?

Thanks.

CodePudding user response:

The compiler uses both parameter to deduce T, and because neither nullptr nor NULL are of type int* there is a conflict between the types deduced from &i and from nullptr / NULL.

Note that nullptr is of type nullptr_t. It can be converted to any other pointer type, but nullptr_t is a distinct type.

Since C 20 you can use std::type_identity to establish a non-deduced context:

#include <type_traits>

template<typename T>
void f(const T* t1, const std::type_identity_t<T>* t2) {}

int main() {
    const int* x;
    f(x,nullptr);  // calls f<int>
}

The second parameter will then not be used to deduce T. Whether this is really what you want depends on details of f. Before C 20, the trait is rather simple to write yourself (see possible implementation).

CodePudding user response:

I thought of sharing my comment. Like the way of your polymorphism using multiple comments :) at stackoverflow.

#include <iostream>
using namespace std;
template<typename T>
// FIRST PARAMETER AND SECOND PARAMETER NEEDS TO BE A POINTER USING SAME TYPE const T*
void f(const T* t1, const T* t2)
{
    return;
}
int main()
{
    int i = 1;
    f( &i, (int*)NULL );
    f<int>( &i, NULL );
    // f( &i, NULL );   // PASSING int* and char*
    float f1 = 20.22;
    f<float>( &f1, NULL);
    return 0;
}
/* g  .exe -Wall -g 73526963.cpp -o ./a.out
 * OR
 * g       -Wall -g 73526963.cpp -o ./a.out
 * LEARN debugging using gdb/dbx/gdb.exe based on your operating system.
 * Know the prototype of the function and polymorphism using ptype/where for parameters inside gdb.
$ gdb ./a.out
Reading symbols from ./a.out...
(gdb) break main
Breakpoint 1 at 0x10040108d: file 73526963.cpp, line 11.
(gdb) run
Starting program: ./a.out
[New Thread 936.0x474]
[New Thread 936.0x634]
[New Thread 936.0x480]
[New Thread 936.0x2578]

Thread 1 "a.out" hit Breakpoint 1, main () at 73526963.cpp:11
warning: Source file is more recent than executable.
11              int i = 1;
(gdb) next
12              f( &i, (int*)NULL );
(gdb) step
f<int> (t1=0xffffcbec, t2=0x0) at 73526963.cpp:7
7               return;
(gdb) ptype t1
type = const int *
(gdb) ptype t2
type = const int *
(gdb) next
8       }
(gdb)
main () at 73526963.cpp:13
13              f<int>( &i, NULL );
(gdb) step
f<int> (t1=0xffffcbec, t2=0x0) at 73526963.cpp:7
7               return;
(gdb) ptype t1
type = const int *
(gdb) ptype t2
type = const int *
(gdb) next
8       }
(gdb)
main () at 73526963.cpp:15
15              float f1 = 20.22;
(gdb)
16              f<float>( &f1, NULL);
(gdb) step
f<float> (t1=0xffffcbe8, t2=0x0) at 73526963.cpp:7
7               return;
(gdb) ptype t1
type = const float *
(gdb) ptype t2
type = const float *
(gdb) next
8       }
(gdb)
main () at 73526963.cpp:17
17              return 0;
(gdb)
18      }
(gdb)
0x0000000180049b7d in _cygwin_exit_return () from /usr/bin/cygwin1.dll
(gdb)
Single stepping until exit from function _cygwin_exit_return,
which has no line number information.
[Thread 936.0x480 exited with code 0]
[Thread 936.0x474 exited with code 0]
[Thread 936.0x2024 exited with code 0]
[Thread 936.0x634 exited with code 0]
[Inferior 1 (process 936) exited normally]
(gdb) quit
$ # We can use b/break or stop in or stop at or step or s or next or n or continue or c based on related available debugger at current OS.
*/
  • Related