explicit specialization: why can't with char *?

why? It tells me: error: no instance of function template "hey" matches the specified type.

1
2
3
4
template <class T>
T hey(const T);

template <> char* hey<char *>(const char*);
I find that if i delete the const in the explicit specialization, it's OK. but why?
anybody?
1
2
3
4
5
6
7
8
template < typename  T > T hey( const T ) ; // 1

template <> int hey<int>( const int ) ; // 2

template <> char* hey<char*>( char* const ) ; // 3

typedef char* cstr ;
template <> cstr hey<cstr>( const cstr ) ; // same as 3 


Note 1: What can we gain by const-qualifying a parameter that is passed by value?

Note 2: Override, do not specialize. http://www.cplusplus.com/forum/beginner/100227/
if when the const T comes to pointers that const qualifier qulifies that the pointer's addr, why my following code works.
P.S. it is technically, i just wanna know the mechanism not the necessary for use it or what, as a beginner.

1
2
3
4
5
6
void hahaha(const T a){
	std::cout << a << std::endl;
}
template <> void hahaha<const int*>(const int *a){
	std::cout << *a << " : " << a << std::endl;
}


and in my mind, the specialization should be
1
2
3
template <> void hahaha<const int*>(const int const *a){
	std::cout << *a << " : " << a << std::endl;
}

and of course, it works too. I wonder why the former one works as well, now that it's addr is not const.
Last edited on
Let us go over the basics once again:

There is only one difference (which is manifested only as a pure implementation detail) between:

void foo( int a ) { /* a can be modified in the function */ }
and
void foo( const int a ) { /* a can't be modified in the function */ }

In both cases, the parameters are passed by value (the function gets a copy). To the caller of the function, there is no semantic difference between the two. From the caller's perspective, the two functions are indistinguishable.

So the two declarations:
1
2
void foo( int a ) ;
void foo( const int a ) ;

are treated as two declarations of the same function.

If we try to provide two definitions
1
2
3
void foo( int a ) { /*....*/ }  

void foo( const int a ) { /* ... */ }

we would get an error: the same function is being multiply defined.
http://coliru.stacked-crooked.com/a/2cc395d6eba4c5a9

Which was the point of my earlier question:
What can we gain by const-qualifying a parameter that is passed by value?

template < typename T > void hahaha( const T a ) { /* ... */ }
is indistinguishable from:
template < typename T > void hahaha( T a ) { /* ... */ }

=================================================

Two, in a type specifier, the position of the const qualifier prior to an asterisk (*) does not matter; it always applies to what is on the left of the asterisk. Kernighan and Ritchie defined the C grammar that way, and it is still that way in both C and C++.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int i = 3 ; // int

const int c1 = 4 ; // const int
int const c2 = 4 ; // const int (alternate syntax)

int* p = &i ; // pointer to int

const int* pc1 = &c1 ; // pointer to const int
int const* pc2 = pc1 ; // pointer to const int (alternate syntax)

int* const cp1 = &i ; // const pointer to int

const int* const cpc1 = &c1 ; // const pointer to const int
int const* const cpc2 = cpc1 ; // const pointer to const int (alternate syntax) 


Just pick one style that appeals to you, and then use it consistently.

This is an error, both the const qualifiers apply to 'int':
const int const* a = &c ; // *** error, duplicated const qualifier

This too results in the same error:
> and in my mind, the specialization should be
1
2
3
> template <> void hahaha<const int*>(const int const *a){
>	std::cout << *a << " : " << a << std::endl;
> } 
Thanks for ur time and patience!
and i'm sorry that i made a mistake when question.
1
2
3
template <> void hahaha<const int*>(const int const *a){
	std::cout << *a << " : " << a << std::endl;
}//wrong one 


the correct one should be:
1
2
3
4
//what i wanna ask.
template <> void hahaha<const int*>(const int * const a){
	std::cout << *a << " : " << a << std::endl;
}




and allow me question again:

if the template be like this:
1
2
3
void hahaha(const T a){
	...
}

and if i make specialization like below:
1
2
3
template <> void hahaha<int*>(int * const a){
	...
}

make T type int *, so the const should be limiting the change of the pointer addr , not the value it points to.

and if the specialization be like this:
1
2
3
template <> void hahaha<const int*>(const int * const a){
	...
}

obviously, i intended to make T the type const int*, and the parenthesis inside should be, in my opinion, (const int * const a). and this works well at compiler, but i occationally met another version, which i think is wrong, but the compiler let it happen:
1
2
3
template <> void hahaha<const int*>(const int * a){
	...
}

this time the T is type int* in terms of the compiler tell. but it conflict the <const int *>. it should occur an error.

why it works?
you said the caller function can't aware of the const and non-const. but here is in the called function parameter list.
Last edited on
> if the template be like this:
> template < typename T > void hahaha( const T a ) ;

It is equivalent to: template < typename T > void hahaha( T a ) ;


> and if i make specialization like below:
> template <> void hahaha<int*>( int* const a ) ;

That is equivalent to: template <> void hahaha<int*>( int* a ) ;


> and if the specialization be like this:
> template <> void hahaha<const int*>( const int* const a ) ;

Which is equivalent to: template <> void hahaha<const int*>( const int* a ) ;


> but i occationally met another version:
> template <> void hahaha<const int*>( const int* a ) ;

This is not another bversion; it is the same as:
template <> void hahaha<const int*>( const int* const a ) ;


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// these two declarations are indistinguishable
template < typename T > void hahaha( T a ) ;
template < typename T > void hahaha( const T a ) ;

// these two declarations are indistinguishable
template <> void hahaha<int*>( int* a ) ;
template <> void hahaha<int*>( int* const a ) ;

// these two are declarations indistinguishable
template <> void hahaha<const int*>( const int* a ) ;
template <> void hahaha<const int*>( const int* const a ) ;


/////////////////////////////////////////////////////////////////////////

template < typename T > void hahaha( T a ) { /* ... */ } // definition

// *** error: redefinition of 'template < typename T > void hahaha( T )'
template < typename T > void hahaha( const T a ) { /* ... */ }

/////////////////////////////////////////////////////////////////////////
template <> void hahaha<int*>( int* a ) { /* ... */ }

// *** error: redefinition of 'template <> void hahaha<int*>( int* )'
template <> void hahaha<int*>( int* const a ) { /* ... */ }

/////////////////////////////////////////////////////////////////////////
template <> void hahaha<const int*>( const int* const a ) { /* ... */ }

// *** error: redefinition of 'template <> void hahaha<const int*>( const int* )'
template <> void hahaha<const int*>( const int* a ) { /* ... */ }

http://coliru.stacked-crooked.com/a/26a4ce6e9202664a


Perhaps an example without templates would help clarify this (templates and explicit specializations are merely incidental; the crux of the matter lies elsewhere):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <type_traits>

void foo( int ) ; // declares 'foo' to be of type void(int)
void bar( const int ) ; // declares 'bar' to be of type void(int)

int main()
{
    using function_type_one = void(int) ;
    using function_type_two = void( const int ) ;

    // both function_type_one and function_type_two is the same type
    std::cout << std::boolalpha
        << std::is_same<function_type_one,function_type_two>::value << '\n' ; // true

    function_type_one* fn1 = &foo ;
    fn1(10) ; // foo( const int )

    fn1 = &bar ;
    fn1(10) ; // bar( int )

    function_type_two* fn2 = &foo ;
    fn2(10) ; // foo( const int )

    fn2 = &bar ;
    fn2(10) ; // bar( int )

    fn1 = fn2 ; // fine; pointers are of the same type
    fn2 = fn1 ; // fine
}

void foo( const int a ) // defines void foo( int )
{
    std::cout << "foo( const int )\n" ;
    // a = 45 ; // error: *** can't assign to const object
}

void bar( int a ) // defines void bar( int )
{
    std::cout << "bar( int )\n" ;
    a = 45 ; // fine
}

http://coliru.stacked-crooked.com/a/1f677ee69fed0245
Topic archived. No new replies allowed.