Search code examples
c++c++11templatesreference

Why can't pass object reference to a template?


Here's my code:

#include <iostream>
#include <vector>

struct LogParamScaler
{
};

template <LogParamScaler &T>
struct QRange {
    
};

int main()
{
    LogParamScaler mLogParamScaler;
    QRange<mLogParamScaler> qRange;
}

but it says to me & mLogParamScaler' is not a valid template argument of type 'LogParamScaler&' because 'mLogParamScaler' has no linkage

I'm on c++11, can't pass by reference? Tried also with pointer, but seems I can't as well:

#include <iostream>
#include <vector>

struct LogParamScaler
{
};

template <LogParamScaler *T>
struct QRange {
    
};

int main()
{
    LogParamScaler mLogParamScaler;
    QRange<&mLogParamScaler> qRange;
}

What's the way to do it using templates? I must use them because QRange<mLogParamScaler> will be used as "type" for another object/template, i.e. createObject<QRange<mLogParamScaler>>.


Solution

  • Templates are instantiated at compile time. So every argument needs to be "known" at compile time. For non-type template parameters this means every argument must have static storage duration (simple terms: the variable passed must be alive for the entire duration of the program).

    In C++11 you can pass a global variable:

    struct LogParamScaler {};
    
    template <LogParamScaler &T>
    struct QRange {};
    
    LogParamScaler gLogParamScaler;
    
    int main()
    {
        QRange<gLogParamScaler> gRange;
    }
    

    Since C++17 you can also pass a local variable with static storage duration:

    struct LogParamScaler {};
    
    template <LogParamScaler &T>
    struct QRange {};
    
    int main()
    {
        static LogParamScaler mLogParamScaler;
        QRange<mLogParamScaler> qRange;
    
    }
    

    If you don't need the template parameter to be a reference type you can have this since C++20:

    struct LogParamScaler {};
    
    template <LogParamScaler T>
    struct QRange {};
    
    
    int main()
    {
        QRange<LogParamScaler{}> qRange;
    }