const references in c++ templates
Remove the reference:
template<typename T>
void Test(const typename std::remove_reference<T>::type & param)
{
param = 20;
}
Now it works as expected.
C++: template function with explicitly specified reference type as type parameter
§8.3.2 [dcl.ref]/p6:
If a typedef-name (7.1.3, 14.1)* or a decltype-specifier (7.1.6.2)
denotes a type TR that is a reference to a type T, an attempt to
create the type “lvalue reference to cv TR” creates the type “lvalue
reference to T”, while an attempt to create the type “rvalue reference
to cv TR” creates the type TR.
This is known as reference collapsing and is introduced in C++11. In C++03, your code would be ill-formed, but some compilers supported it as an extension.
Note that in const T &
, the const
applies to the type T
, so when T
is int &
, the const
would apply to the reference type itself (which is meaningless as references are immutable anyway), not the type referred to. This is why the reference collapsing specification ignores any cv-qualifiers on TR
.
*A template type parameter is a typedef-name, per §14.1 [temp.param]/p3:
A type-parameter whose identifier does not follow an ellipsis
defines its identifier to be a typedef-name (if declared with
class
ortypename
) or template-name (if declared with
template
) in the scope of the template declaration.
How can const be applied to template argument types outside of the parameter list in C++?
Template type substitutions are not textual, so do not think of them in terms of the textual type definition.
In your example, T is deduced to be int *
- let's call it intptr
. You are making const
reference to it, so return value becomes const intptr&
. That means, that the pointer itself can't be modified through this reference, but the value it points to can be modified.
Last, but not the least, you could have easily verifed your assumptions before asking the question :)
How to use a const reference as template parameter?
I won't directly answer your question, but I dare to guess what you really need to hear :)
First, having references as types of templates is not usually a good idea. If you want to make a wrapper, it makes sense to have a reference on a wrapped inside your class, but it is still better to keep template parameter type to be a value type, not a reference type. Having said that, if you are really sure you want to have reference type as a parameter, you might want to play with std::decay
.
Then, I see you have partial template specialization here. From the code you posted it is not clear if you actually need it or not. I personally love to keep things simple, so I'd suggest you're good without it. In this case just parametrize your class on the one and only type T
.
As a side note, do not declare your functions inline
. Compiler knows best for you. And methods defined in scope of a class are inline
by default anyway. Forget that inline
means "please make this code faster". This actually means "this symbol might appear in several translation units, please pick a single definition for me".
Finally, boost is a great library, but I don't see how you need it here. All standard containers provide all the necessary type aliases in them, just ask.
Here is the compiling code simplified according to my comments:
#include <vector>
template <class T>
class matrix_wrapper
{
public:
using reference = const T&;
using vector_type_ref = typename T::reference;
using vector_type_const_ref = typename T::const_reference;
matrix_wrapper(reference data) : m_data(data) {}
vector_type_const_ref operator[](size_t i) const
{
return m_data[i];
}
// BTW this won't compile for non-const objects, since you store a const
// reference to the container, but that's a different story
vector_type_ref operator[](size_t i)
{
return m_data[i];
}
reference data()
{
return m_data;
}
protected:
reference m_data;
};
void test(const std::vector<std::vector<int>>& data)
{
matrix_wrapper<std::vector<std::vector<int>>> matrix(data);
}
int main()
{
std::vector<std::vector<int>> v(10, std::vector<int>(10, 1));
test(v);
}
See live demo here: https://wandbox.org/permlink/tmemloS6wCHZlhNY
I see that you declared v
in main()
as a vector
of int
s, but you accept a vector
of double
in test()
. I assumed this is a misprint and fixed the types.
I completely agree with @NathanOliver about 1D/2D thing, but that's again a different story.
How can I declare a template constant type?
C++11:
template <typename T>
using Constant = const T;
Constant<int> i = 1;
//! i = 2; // error: assignment of read-only variable 'i'
C++03:
template <typename T>
struct Constant
{
typedef const T type;
};
Constant<int>::type i = 1;
A good way to organize a code involving const references with limited scope and templates in C++
Invert control flow and a runtime to compile time dispatcher.
This is insanely complex in c++11, and modestly complex in c++14.
In c++14 you can get:
pick( some_boolean_statement,
&getRef<TYPE_A>,
&getRef<TYPE_B>
)([&](auto* getRef){
const auto& ref = getRef();
doStuff(ref);
});
but basically every step along that way is a pain in c++11.
Another approach would be to make a std (c++17) or boost (c++03) variant that stores a pointer to TYPE_A
or TYPE_B
. Then use visit
; but even here, you'd need an auto lambda to keep your code short.
The simplest c++14 version is:
auto doWork = [&](const auto& ref) {
doStuff(ref);
};
if (some_boolean_statement) {
doWork(getRef<TYPE_A>());
} else {
doWork(getRef<TYPE_B>());
}
Related Topics
Unordered_Map Hash Function C++
Non-Class Rvalues Always Have Cv-Unqualified Types
Std::List<>::Sort()' - Why the Sudden Switch to Top-Down Strategy
Construct Path for #Include Directive with MACro
When Should I Use C++14 Automatic Return Type Deduction
Fast N Choose K Mod P for Large N
Are There Practical Uses for Dynamic-Casting to Void Pointer
What Is Copy Elision and How Does It Optimize the Copy-And-Swap Idiom
How to Declare Constexpr Extern
Blending Does Not Remove Seams in Opencv
Tackling Class Imbalance: Scaling Contribution to Loss and Sgd
Function Overloading Based on Value VS. Const Reference
Constant References with Typedef and Templates in C++
Does Returning a Local Variable Return a Copy and Destroy the Original(Nrvo)
How to Hook Windows Functions in C/C++
What Is the Correct Way of Reading from a Tcp Socket in C/C++