0

I've made a variadic template that finds a string based on a "key" and then replaces placeholder text with the parameters it is given. It works as expected, but I would like to ideally define the functions in a CPP file... Is this possible? I know that the arguments (if any) will always be strings, if that helps.

I know there has been many discussions on the subject of defining templates in a CPP file, and many of those provide example on how to do this... but I can't find any that discuss defining templates that use parameter packs in CPP files.

Here is my code...

StringConverter.h

#include <string>

class StringConverter
{
public:
    template<typename... Strings>
    std::string GetModifiedString(
        const std::string& OriginalKey, 
        const Strings&... rest);

private:
    const std::string FindOriginal(
        const std::string& Key) const;

    void ReplaceValue(
        std::string& OriginalString);

    template<typename... Strings>
    void ReplaceValue(
        std::string& OriginalString, 
        const std::string& arg = "", 
        const Strings&... rest);
        
};

StringConverter.cpp

#include "StringConverter.h"

#include <iostream>

// Defining this here causes compile errors...
template<typename... Strings>
std::string StringConverter::GetModifiedString(
    const std::string& OriginalKey, 
    const Strings&... rest)
{
    std::string modified_string = FindOriginal(OriginalKey);
    ReplaceValue(modified_string, rest...);
   
    return modified_string;
}

const std::string StringConverter::FindOriginal(
    const std::string& Key) const
{
    if(Key == "Toon")
    {
        return "This is example %s in my program for Mr. %s.";
    }
    
    return "";
}

void StringConverter::ReplaceValue(
    std::string& OriginalString)
{
    (void)OriginalString;
}

// Defining this here causes compile errors...
template<typename... Strings>
void StringConverter::ReplaceValue(
    std::string& OriginalString, 
    const std::string& arg, 
    const Strings&... rest)
{
    const std::string from = "%s";

    size_t start_pos = OriginalString.find(from);
    if(start_pos != std::string::npos)
    {
        OriginalString.replace(start_pos, from.length(), arg);
    }
    
    ReplaceValue(OriginalString, rest...);
}

Main.cpp

#include <iostream>
#include "StringConverter.h"

int main()
{
    StringConverter converter;
    
    std::cout << converter.GetModifiedString("Toon", "5", "Jimmy") << std::endl;    

    return 0;
}
Ricky
  • 823
  • 2
  • 14
  • 31
  • You have to wait for C++20 modules. There is way to overcome this in some corner cases, but IMO your case doesn't fit into this scenario. – Marek R Dec 01 '22 at 17:23
  • 1
    The template definition must be available at the point you want to use it, well, at least in one case for each instantiation... – Quimby Dec 01 '22 at 17:27
  • @Quimby You've rushed a bit with closing question. There are alternative solutions to his problem. Like for example provide template which will convert arguments to initialize_list and call none template API. This is not solution matching problem from a title, but a good solution for his actual problem. – Marek R Dec 01 '22 at 17:32
  • @MarekR Okay, I apologize, question reopened, feel free to add the answer. – Quimby Dec 01 '22 at 17:49
  • @MarekR I'm also not sure how I would make the template definition available for a parameter pack... (In this case a parameter pack of all strings)... and the other discussions on templates defined in CPP files don't discuss parameter packs. – Ricky Dec 01 '22 at 17:51
  • Why do you need it to be in the cpp file? – Kyle Dec 01 '22 at 18:04
  • @Kyle The real program uses different objects throughout the process of modifying the string. I would ideally like to avoid mucking up StringConverter.h with the includes required for those objects. – Ricky Dec 01 '22 at 18:08
  • You already have mentioned, that defining templates in cpp are already discussed. What is special with parameter packs? And it is also not related to templates, as you can make the template declaration in a header file, put the code in cpp file and instantiate all needed instances your self in that cpp file. Quite clear, all that makes no sense, normally, but you simply violate basic c++ rules. And this is discussed more than 1000 times... as this, I didn't see anything new in your question and vote to close. – Klaus Dec 01 '22 at 18:10
  • You have to instantiate the template. `template std::string StringConverter::GetModifiedString( const std::string& OriginalKey, const char (&)[2], const char(&)[6]); ` – KamilCuk Dec 01 '22 at 19:07

0 Answers0