Here's a minimal code example to show what I'm attempting that works, but not how I'd like it to:
#include <string>
#include <type_traits>
#include <iostream>
struct string_tag {
using R=const std::string;
};
struct int_tag {
using R=const int;
};
template <bool TS>
class Wibble {
public:
template<typename TAG>
typename TAG::R getValue(TAG);
};
template <bool TS>
template <typename TAG>
typename TAG::R Wibble<TS>::getValue(TAG) {
if constexpr (std::is_same<TAG, string_tag>::value) {
return "hello";
}
if constexpr (std::is_same<TAG, int_tag>::value) {
return 42;
}
}
// instantiate classes
template class Wibble<true>;
template class Wibble<false>;
int main () {
Wibble<true> tw;
Wibble<false> fw;
std::cout << "tw string: " << tw.getValue(string_tag{}) << std::endl;
std::cout << "tw int: " << tw.getValue(int_tag{}) << std::endl;
std::cout << "fw string: " <<fw.getValue(string_tag{}) << std::endl;
std::cout << "fw int: " << fw.getValue(int_tag{}) << std::endl;
}
The part I want to change is the ugly function template definition with all the constexpr
logic. I'd like to be able to define the different specializations in TAG
standalone, but doing this gives me redefinition of ...
errors.
Syntax like the following would be nice:
template<bool TS>
template<>
string_tag::R Wibble<TS>::getValue(string_tag) {
return "hello";
}
but computer says "no".
CodePudding user response:
I gave it a thought, read language specs etc. and the following things come to my mind:
Class template has to be specialized in order to specialize member function template. Period. This cannot be overcome with concepts, or at least I haven't found a way. I guess you don't want to replicate the code for each case of TS. Maybe it can be done automagically with some Alexandrescu-style metaprogramming techniques, but I can't think of anything right off the bat.
Overloads instead of templates are a good alternative but I'm guessing you'd like to be able to add them out-of-line, instead of inside the class...
Then I recalled David Wheeler: “All problems in computer science can be solved by another level of indirection." So let's add one:
namespace detail
{
template<typename TAG> auto getValue(TAG);
template<>
auto getValue<string_tag>(string_tag)
{
return "hi";
}
template<>
auto getValue<int_tag>(int_tag)
{
return 42;
}
template<>
auto getValue<double_tag>(double_tag)
{
return 1324.2;
}
}
template<bool TS>
template<typename TAG>
auto Wibble<TS>::getValue(TAG t)
{
return detail::getValue(t);
}
https://godbolt.org/z/GsPK4MP8M Hope it helps.