Museful
Museful

Reputation: 6959

Function template specialization with const ref arguments

The following code compiles fine.

#include <iostream>

struct rgb8{
    uint8_t r() const {return 0;};
};


template<typename L, typename P>
L pixelToLevel(P p) {
    return static_cast<L>(p);
}

template<>
uint8_t pixelToLevel<uint8_t, rgb8>(rgb8 p) {  //       <---------- line X
    return pixelToLevel<uint8_t, uint8_t>(p.r());
}


int main()
{
  pixelToLevel<uint8_t>(rgb8());
  return 0;
}

But if in line X I change rgb8 p to const rgb8& p, it fails to compile.

(The exact compiler error generated depends on whether or not the explicit template argument rgb8 is also changed to const rgb8&.)

How can I get it to compile if I want to pass p by reference rather than by value on line X?

Upvotes: 1

Views: 201

Answers (2)

songyuanyao
songyuanyao

Reputation: 173024

You need to change the template parameter in the declaration of specialization, and template argument when calling it too. Otherwise the primary template would be called instead. e.g.

template<>
uint8_t pixelToLevel<uint8_t, const rgb8&>(const rgb8& p) {  //       <---------- line X
    return pixelToLevel<uint8_t, uint8_t>(p.r());
}

then

pixelToLevel<uint8_t, const rgb8&>(rgb8());

LIVE


EDIT

Given pixelToLevel<uint8_t>(rgb8());, template argument deduction is performed with primary template and P is deduced as rgb8 (it won't be deduced as const rgb8& with current primary template's parameter declaration), then the specialization version won't be called.

You can apply overloading instead of template specialization. e.g.

template<typename L, typename P>
L pixelToLevel(P p) {
    return static_cast<L>(p);
}

template<typename L>
L pixelToLevel(const rgb8& p) {  //       <---------- line X
    return pixelToLevel<L, uint8_t>(p.r());
}

Then pixelToLevel<uint8_t>(rgb8()); would select the 2nd overload.

LIVE

Upvotes: 1

theWiseBro
theWiseBro

Reputation: 1529

An alternate solution to @songyuanyao's would be

template<typename L, typename P>
L pixelToLevel(const P& p) {
    return static_cast<L>(p);
}

Upvotes: 1

Related Questions