Type conversion in class template instantiation - c++

I have a template class item which stores objects of various types T. It also attaches attributes to those objects in instantiation/initialization.
One special thing I want to achieve is that whenever item sees a const char *, it deems and stores it as a std::string. This could be done, as follows.
But in type checking, I found an item instantiated from a const char * is still different in type from an item instantiated from a std::string. Please see the last line with comment false, which I want to make true.
#include <iostream>
#include <string>
#include <type_traits>
using namespace std;
template<typename T>
using bar = typename std::conditional<std::is_same<T, const char *>::value,
string, T>::type;
template<typename T>
class item
{
bar<T> thing;
// other attributes ...
public:
item(T t) : thing(t) {}
// other constructors ...
bar<T> what() const
{
return thing;
}
};
int main()
{
auto a = item("const char *"); // class template argument deduction (C++17)
auto b = item(string("string")); // class template argument deduction (C++17)
cout << std::boolalpha;
cout << (typeid(a.what()) == typeid(b.what())) << endl; // true
cout << (typeid(a) == typeid(b)) << endl; // false
}
My question is: is it possible to make any change to the template class item so that an item instantiated from a const char * becomes the same in type with an item instantiated from a std::string?
In other words, can I make any change to the design of the template class item so that typeid(a) == typeid(b) evaluates to true ?
Thank you !
Note: This follows up a previous question on template function. But I think there's something intrinsically different that it deserves a stand-alone question.
Edit: My goal is to change the design of the template class item (e.g. item signatures), not the code in main, which is assumed to be supplied by users. I want to make life easier for the users of item, by not asking them to explicitly supply type T in instantiation. This is meant to be done by C++17 template class argument deduction or some equivalent workarounds.
Update: Thank you all! Special thanks to #xskxzr, whose one-liner exactly solves my question. With user-defined deduction guides for class template argument deduction, I don't even need the bar<T> technique in my previous code. I put updated code below for your comparison.
#include <iostream>
#include <string>
using namespace std;
template<typename T>
class item
{
// UPDATE: no bar<T> needed any more
T thing;
// other attributes ...
public:
item(T t) : thing(t) {}
// other constructors ...
// UPDATE: no bar<T> needed any more
T what() const
{
return thing;
}
};
item(const char *) -> item<std::string>; // UPDATE: user-defined deduction guide !
int main()
{
auto a = item("const char *"); // class template argument deduction (C++17)
auto b = item(string("string")); // class template argument deduction (C++17)
cout << std::boolalpha;
cout << (typeid(a.what()) == typeid(b.what())) << endl; // true
cout << (typeid(a) == typeid(b)) << endl; // UPDATE: now true !
}

You can add a user-defined deduction guide:
item(const char *) -> item<std::string>;
With this deduction guide, a will be deduced to be item<std::string>.

No, you can't directly make the typeid of two templated objects using different template arguements be the same.
But to achieve your end goal you can use a factory like pattern. It could look something like this:
template<typename T, typename R = T>
item<R> make_item(T&& t)
{
return item<T>(std::forward<T>(t));
}
// Specialization for const char *
template<>
item<std::string> make_item(const char *&& str)
{
return item<std::string>(str);
}
The downside with this approach is that you'll need to construct all of your objects with this factory. And if you have a lot of exceptions you'll need to make a specialization for each exception.

This is more a guess than an answer, but I'd say no. Templates are expanded at compile time, so because you are creating an
item<const char*>
and an
item<std::string>
then the code that gets expanded looks something like
class item1
{
bar<const char*> thing;
// other attributes ...
public:
item(const char* t) : thing(t) {}
// other constructors ...
bar<const char*> what() const
{
return thing;
}
};
class item2
{
bar<std::string> thing;
// other attributes ...
public:
item(std::string t) : thing(t) {}
// other constructors ...
bar<std::string> what() const
{
return thing;
}
};
(More or less; they wouldn't actually be called item1 and item2)
How you chose to evaluate these two types is up to you, but to the compiler they are in fact two different types.

Ok, I'd never seen or used std::conditional before so I wasn't sure what that was doing, but after reading up on it and playing around with your code I did get it to "work" by using
bar<T>
as the template type. So instead of
auto a = item<const char*>("const char *");
auto b = item<string>(string("string"));
I did
auto a = item<bar<const char*>>("const char *");
auto b = item<bar<string>>(string("string"));
The thing is you need the template type to be the same in both cases, meaning the type needs to resolve to std::string before the template gets expanded. As long as you use your conditional, you can define any type.
auto c = item<bar<int>>(5);
Not sure that's a good solution (which is why I said "work"), but see my other answer about the class types actually being different.

Related

Can both a 'constexpr'-marked variable and a variable of static-storage duration allowed to be stored through a class type with a deduction guide?

Consider the following piece of code:
template <typename T>
struct wrap {
T thing;
constexpr wrap(T thing) : thing(thing) {}
};
template <typename T>
wrap(const T&) -> wrap<T>;
template <wrap V>
void fun();
struct X {
int a;
};
int main() {
constexpr auto a1 = &X::a;
static const auto a2 = &X::a;
fun<a1>();
fun<a2>(); // Doesn't compile
}
Now the thing is that one can successfully pass a1 through wrap without having to state the template parameter explicitly, but not a2 which has static-storage duration.
If I change the above deduction guide to this:
template <typename T>
wrap(const T&) -> wrap<const T&>; // <-- Note the 'const T&' here instead of plain 'T'
Then one is able to pass a2 but not a1.
If possible, how to modify the above code so that one is able to pass both a1 and a2 respectively without having to explicitly state the types like fun<wrap<decltype(a1)>{a1}>() or fun<wrap<const decltype(a2)&>{a2}>()?
Sure, it's possible. However, before I explain the solution, please allow me to suggest that you have made the problem unnecessarily difficult by insisting on a particular interface which is not (in my opinion) actually cleaner than the alternatives. Essentially, you are asking for fun<arg> to either take arg by value or by reference, depending on which one is actually well-formed. In the case of a1, it may only be taken by value; it cannot be taken by reference because it doesn't have static storage duration. In the case of a2, it cannot be taken by value because it wasn't declared constexpr, but can be taken by reference because it has static storage duration.
The code using your proposed version of fun is difficult to read, because the reader, seeing fun<arg>, does not immediately know whether arg is being taken by value or by reference. The reader must infer which one it is, based on the reader's own knowledge of whether arg is a permitted non-type template parameter by value or by reference. Furthermore, some arguments may qualify as either, and in that case the reader would also have to know which default the implementer of fun has selected for that case, in order to know what is going on.
Again, this is my opinion only: it would be much simpler if you wrote separate functions, perhaps calling them fun_val and fun_ref, where fun_val<a1>() and fun_ref<a2>() are well-formed. For this, we should define two wrapper classes, one which takes the argument by value, and one by reference:
template <typename T>
struct wrap_value {
using value_type = T;
T thing;
constexpr wrap_value(T thing) : thing(thing) {}
};
template <typename T>
wrap_value(const T&) -> wrap_value<T>;
template <typename T>
struct wrap_reference {
using value_type = T;
const T& thing;
constexpr wrap_reference(const T& thing) : thing(thing) {}
};
template <typename T>
wrap_reference(const T&) -> wrap_reference<T>;
template <wrap_value V>
void fun_val() {
std::cout << "value\n";
}
template <wrap_reference V>
void fun_ref() {
std::cout << "reference\n";
}
struct X {
int a;
};
int main() {
constexpr auto a1 = &X::a;
static const auto a2 = &X::a;
static const int x = 42;
fun_val<a1>(); // OK
fun_ref<a1>(); // Error
fun_val<a2>(); // Error
fun_ref<a2>(); // OK
fun_val<x>(); // OK; uses value of x
fun_ref<x>(); // OK; uses address of x
}
Now, if you insist on having a single name fun, then the key is to recognize that a1 and a2 have the same type, so a single application of CTAD will never be able to figure out the correct wrapper type to make the invocation well-formed. Instead, you have to use SFINAE with two overloads: the one that is invalid for the given template argument (because it takes the argument by value (resp. reference) that cannot be taken by value (resp. reference)) is discarded. Basically, rename both fun_val and fun_ref in the above example to simply fun:
template <wrap_value V>
void fun() {
std::cout << "value\n";
}
template <wrap_reference V>
void fun() {
std::cout << "reference\n";
}
This works fine in the case of a1 and a2, for which only one of the two overloads is a candidate. But in the case of x, it will be ambiguous. Let's say you want to force the by-value overload to be selected in that case. We can do that by inserting a constraint that makes the by-reference overload not a candidate:
template <wrap_reference V> requires(!requires { fun<wrap_value<typename decltype(V)::value_type>(V.thing)>(); })
void fun() {
std::cout << "reference\n";
}
You can view the full working example here.

Generic factory mechanism in C++17

I would like to implement a generic factory mechanism for a set of derived classes that allows me to generically implement not only a factory function to create objects of that class, but also creators of other template classes which take as template arguments one of the derived classes.
Ideally a solution would only use C++17 features (no dependencies).
Consider this example
#include <iostream>
#include <string>
#include <memory>
struct Foo {
virtual ~Foo() = default;
virtual void hello() = 0;
};
struct FooA: Foo {
static constexpr char const* name = "A";
void hello() override { std::cout << "Hello " << name << std::endl; }
};
struct FooB: Foo {
static constexpr char const* name = "B";
void hello() override { std::cout << "Hello " << name << std::endl; }
};
struct FooC: Foo {
static constexpr char const* name = "C";
void hello() override { std::cout << "Hello " << name << std::endl; }
};
struct BarInterface {
virtual ~BarInterface() = default;
virtual void world() = 0;
};
template <class T>
struct Bar: BarInterface {
void world() { std::cout << "World " << T::name << std::endl; }
};
std::unique_ptr<Foo> foo_factory(const std::string& name) {
if (name == FooA::name) {
return std::make_unique<FooA>();
} else if (name == FooB::name) {
return std::make_unique<FooB>();
} else if (name == FooC::name) {
return std::make_unique<FooC>();
} else {
return {};
}
}
std::unique_ptr<BarInterface> bar_factory(const std::string& foo_name) {
if (foo_name == FooA::name) {
return std::make_unique<Bar<FooA>>();
} else if (foo_name == FooB::name) {
return std::make_unique<Bar<FooB>>();
} else if (foo_name == FooC::name) {
return std::make_unique<Bar<FooC>>();
} else {
return {};
}
}
int main()
{
auto foo = foo_factory("A");
foo->hello();
auto bar = bar_factory("C");
bar->world();
}
run it
I am looking for a mechanism that would allow me to implement both foo_factory and bar_factory without listing all classes, such that they do not need to be updated once I add for example FooD as an additional derived class. Ideally, the different Foo derivatives would somehow "self-register", but listing them all in one central place is also acceptable.
Edit:
Some clarifications based on comments / answers:
It is necessary in my case to invoke the factories with (something like) a string, since the callers of the factories use polymorphism with Foo / BarInterface, i.e. they don't know about the concrete derived classes. On the other hand in Bar we want to use template methods of the derived Foo classes and facilitate inlining, that's why we really need the templated derived Bar classes (rather than accessing Foo objects through some base-class interface).
We can assume that all derived Foo classes are defined in one place (and a manual registration where we list them all once in the same place is therefore acceptable, if necessary). However, they do not know about the existence of Bar, and in fact we have multiple different classes like BarInterface and Bar. So we cannot create "constructor objects" of Bar and save them in a map the same way we can do it for a foo_factory. What I think is needed is some kind of "compile-time map" (or list) of all the derived Foo types, such that when defining the bar_factory, the compiler can iterate over them, but I don't know how to do that...
Edit2:
Additional constraints that proofed to be relevant during discussion:
Templates and template templates: The Foo are actually templates (with a single class argument) and the Bar are template templates taking a concrete Foo as template argument. The Foo templates have no specializations and all have the same "name", so querying any concrete type is fine. In particular SpecificFoo<double>::name is always valid. #Julius' answer has been extended to facilitate this already. For #Yakk's the same can probably be done (but it will take me some time for figure it out in detail).
Flexible bar factory code: The factory for Bar does a little more than just call the constructor. It also passes some arguments and does some type casting (in particular, it may have Foo references that should be dynamic_cast to the corresponding concrete derived Foo). Therefore a solution that allows to write this code inline during definition of the bar_factory seems most readable to me. #Julius' answer works great here, even if the loop code with tuples is a little verbose.
Making the "single place" listing the Foos even simpler: From the answers so far I believe the way to go for me is having a compile-time list of foo types and a way to iterate over them. There are two answers that define a list of Foo types (or templates) in one central place (either with a types template or with tuples), which is already great. However, for other reasons I already have in the same central place a list of macro calls, one for each foo, like DECLARE_FOO(FooA, "A") DECLARE_FOO(FooB, "B") .... Can the declaration of FooTypes be somehow take advantage of that, so I don't have to list them again? I guess such type lists cannot be declared iteratively (appending to an already existing list), or can it? In the absence of that, probably with some macro magic it would be possible. Maybe always redefining and thus appending to a preprocessor list in the DECLARE_FOO calls, and then finally some "iterate over loop" to define the FooTypes type list. IIRC boost preprocessor has facilities to loop over lists (although I don't want a boost dependency).
For some more context, you can think of the different Foo and it's template argument as classes similar to Eigen::Matrix<Scalar> and the Bar are cost functors to be used with Ceres. The bar factory returns objects like ceres::AutoDiffCostFunction<CostFunctor<SpecificFoo>, ...> as ceres::CostFunction* pointers.
Edit3:
Based on #Julius' answer I created a solution that works with Bars that are templates as well as template templates. I suspect one could unify bar_tmpl_factory and bar_ttmpl_factory into one function using variadic variadic template templates (is that a thing?).
run it
TODO:
combine bar_tmpl_factory and bar_ttmpl_factory
the point Making the "single place" listing the Foos even simpler from above
maybe replacing the use of tuples with #Yakk's types template (but in a way such that the creator function can be defined inline at the call site of the loop over all foo types).
I consider the question answered and if anything the above points should be separate questions.
template<class...Ts>struct types_t {};
template<class...Ts>constexpr types_t<Ts...> types{};
that lets us work with bundles of types without the overhead of a tuple.
template<class T>
struct tag_t { using type=T;
template<class...Ts>
constexpr decltype(auto) operator()(Ts&&...ts)const {
return T{}(std::forward<Ts>(ts)...);
}
};
template<class T>
constexpr tag_t<T> tag{};
this lets us work with types as values.
Now a type tag map is a function that takes a type tag, and returns another type tag.
template<template<class...>class Z>
struct template_tag_map {
template<class In>
constexpr decltype(auto) operator()(In in_tag)const{
return tag< Z< typename decltype(in_tag)::type > >;
}
};
this takes a template type map and makes it into a tag map.
template<class R=void, class Test, class Op, class T0 >
R type_switch( Test&&, Op&& op, T0&&t0 ) {
return static_cast<R>(op(std::forward<T0>(t0)));
}
template<class R=void, class Test, class Op, class T0, class...Ts >
auto type_switch( Test&& test, Op&& op, T0&& t0, Ts&&...ts )
{
if (test(t0)) return static_cast<R>(op(std::forward<T0>(t0)));
return type_switch<R>( test, op, std::forward<Ts>(ts)... );
}
that lets us test a condition on a bunch of types, and run an operation on the one that "succeeds".
template<class R, class maker_map, class types>
struct named_factory_t;
template<class R, class maker_map, class...Ts>
struct named_factory_t<R, maker_map, types_t<Ts...>>
{
template<class... Args>
auto operator()( std::string_view sv, Args&&... args ) const {
return type_switch<R>(
[&sv](auto tag) { return decltype(tag)::type::name == sv; },
[&](auto tag) { return maker_map{}(tag)(std::forward<Args>(args)...); },
tag<Ts>...
);
}
};
now we want to make shared pointers of some template class.
struct shared_ptr_maker {
template<class Tag>
constexpr auto operator()(Tag ttag) {
using T=typename decltype(ttag)::type;
return [](auto&&...args){ return std::make_shared<T>(decltype(args)(args)...); };
}
};
so that makes shared pointers given a type.
template<class Second, class First>
struct compose {
template<class...Args>
constexpr decltype(auto) operator()(Args&&...args) const {
return Second{}(First{}( std::forward<Args>(args)... ));
}
};
now we can compose function objects at compile time.
Next wire it up.
using Foos = types_t<FooA, FooB, FooC>;
constexpr named_factory_t<std::shared_ptr<Foo>, shared_ptr_maker, Foos> make_foos;
constexpr named_factory_t<std::shared_ptr<BarInterface>, compose< shared_ptr_maker, template_tag_map<Bar> >, Foos> make_bars;
and Done.
The original design was actually c++20 with lambdas instead of those structs for shared_ptr_maker and the like.
Both make_foos and make_bars have zero runtime state.
What I think is needed is some kind of "compile-time map" (or list) of
all the derived Foo types, such that when defining the bar_factory,
the compiler can iterate over them, but I don't know how to do that...
Here is one basic option:
#include <cassert>
#include <tuple>
#include <utility>
#include "foo_and_bar_without_factories.hpp"
////////////////////////////////////////////////////////////////////////////////
template<std::size_t... indices, class LoopBody>
void loop_impl(std::index_sequence<indices...>, LoopBody&& loop_body) {
(loop_body(std::integral_constant<std::size_t, indices>{}), ...);
}
template<std::size_t N, class LoopBody>
void loop(LoopBody&& loop_body) {
loop_impl(std::make_index_sequence<N>{}, std::forward<LoopBody>(loop_body));
}
////////////////////////////////////////////////////////////////////////////////
using FooTypes = std::tuple<FooA, FooB, FooC>;// single registration
std::unique_ptr<Foo> foo_factory(const std::string& name) {
std::unique_ptr<Foo> ret{};
constexpr std::size_t foo_count = std::tuple_size<FooTypes>{};
loop<foo_count>([&] (auto i) {// `i` is an std::integral_constant
using SpecificFoo = std::tuple_element_t<i, FooTypes>;
if(name == SpecificFoo::name) {
assert(!ret && "TODO: check for unique names at compile time?");
ret = std::make_unique<SpecificFoo>();
}
});
return ret;
}
std::unique_ptr<BarInterface> bar_factory(const std::string& name) {
std::unique_ptr<BarInterface> ret{};
constexpr std::size_t foo_count = std::tuple_size<FooTypes>{};
loop<foo_count>([&] (auto i) {// `i` is an std::integral_constant
using SpecificFoo = std::tuple_element_t<i, FooTypes>;
if(name == SpecificFoo::name) {
assert(!ret && "TODO: check for unique names at compile time?");
ret = std::make_unique< Bar<SpecificFoo> >();
}
});
return ret;
}
Write a generic factory like the following that allows registration at the class site:
template <typename Base>
class Factory {
public:
template <typename T>
static bool Register(const char * name) {
get_mapping()[name] = [] { return std::make_unique<T>(); };
return true;
}
static std::unique_ptr<Base> factory(const std::string & name) {
auto it = get_mapping().find(name);
if (it == get_mapping().end())
return {};
else
return it->second();
}
private:
static std::map<std::string, std::function<std::unique_ptr<Base>()>> & get_mapping() {
static std::map<std::string, std::function<std::unique_ptr<Base>()>> mapping;
return mapping;
}
};
And then use it like:
struct FooA: Foo {
static constexpr char const* name = "A";
inline static const bool is_registered = Factory<Foo>::Register<FooA>(name);
inline static const bool is_registered_bar = Factory<BarInterface>::Register<Bar<FooA>>(name);
void hello() override { std::cout << "Hello " << name << std::endl; }
};
and
std::unique_ptr<Foo> foo_factory(const std::string& name) {
return Factory<Foo>::factory(name);
}
Note: there is no way to guarantee that the class would be registered. The compiler might decide not to include the translation unit, if there are no other dependencies. It is probably better to simply register all classes in one central place. Also note that the self-registering implementation depends on inline variables (C++17). It is not a strong dependence, and it is possible to get rid of it by declaring the booleans in the header and defining them in the CPP (which makes self-registering uglier and more prone to failing to register).
edit
The disadvantage of this answer, when compared to others, is that it performs the registration during start-up and not during compilation. On the other hand, this makes the code much simpler.
The examples above assume that the definition of Bar<T> is moved above Foo. If that is impossible, then the registration can be done in an initialization function, in a cpp:
// If possible, put at the header file and uncomment:
// inline
const bool barInterfaceInitialized = [] {
Factory<Foo>::Register<FooA>(FooA::name);
Factory<Foo>::Register<FooB>(FooB::name);
Factory<Foo>::Register<FooC>(FooC::name);
Factory<BarInterface>::Register<Bar<FooA>>(FooA::name);
Factory<BarInterface>::Register<Bar<FooB>>(FooB::name);
Factory<BarInterface>::Register<Bar<FooC>>(FooC::name);
return true;
}();
In C++17, we can apply the fold expression to simplify the storing process of generating functions std::make_unique<FooA>(), std::make_unique<FooB>(), and so on into the factory class in this case.
To begin with, for convenience, let us define the following type alias Generator which describes the type of each generating function [](){ return std::make_unique<T>(); }:
template<typename T>
using Generator = std::function<std::unique_ptr<T>(void)>;
Next, we define the following rather generic functor createFactory which returns each factory as a hash map std::unordered_map.
Here I apply the fold expression with the comma operators.
For instance, createFactory<BarInterface, Bar, std::tuple<FooA, FooB, FooC>>()() returns the hash map corresponding to your function bar_factory:
template<typename BaseI, template<typename> typename I, typename T>
void inserter(std::unordered_map<std::string_view, Generator<BaseI>>& map)
{
map.emplace(T::name, [](){ return std::make_unique<I<T>>(); });
}
template<typename BaseI, template<typename> class I, typename T>
struct createFactory {};
template<typename BaseI, template<typename> class I, typename... Ts>
struct createFactory<BaseI, I, std::tuple<Ts...>>
{
auto operator()()
{
std::unordered_map<std::string_view, Generator<BaseI>> map;
(inserter<BaseI, I, Ts>(map), ...);
return map;
}
};
This functor enables us to list FooA, FooB, FooC, ... all in one central place as follows:
DEMO (I also added virtual destructors in base classes)
template<typename T>
using NonInterface = T;
// This can be written in one central place.
using FooTypes = std::tuple<FooA, FooB, FooC>;
int main()
{
const auto foo_factory = createFactory<Foo, NonInterface, FooTypes>()();
const auto foo = foo_factory.find("A");
if(foo != foo_factory.cend()){
foo->second()->hello();
}
const auto bar_factory = createFactory<BarInterface, Bar, FooTypes>()();
const auto bar = bar_factory.find("C");
if(bar != bar_factory.cend()){
bar->second()->world();
}
return 0;
}

C++ templates: Specialized member function to resolve case of ambiguous overload in primary template

I have a template where a function is overloaded so it can handle both an std::string parameter and the type of parameter that the template gets instantiated with. This works fine except when the template is being instantiated with std::string, since this results in two member functions with the same prototype. Thus, I have chosen to specialize that function for this particular case. However, it seems like the compiler (g++ 4.8.1 with flag -std=c++0x) never gets to the point where the specialization is actually overriding the primary template and it complains about the ambiguous overload the before it seems to realize that it should use the specialization. Is there a way to get around this?
#include <iostream>
template<class T>
struct A {
std::string foo(std::string s) { return "ptemplate: foo_string"; }
std::string foo(T e) { return "ptemplate: foo_T"; }
};
template<> //Error!
std::string A<std::string>::foo(std::string s) { return "stemplate: foo_string"; }
int main() {
A<int> a; //Ok!
std::cout << a.foo(10) << std::endl;
std::cout << a.foo("10") << std::endl;
//A<std::string> b; //Error!
//std::cout << a.foo("10") << std::endl;
return 0;
}
This results in compile errors, even if I don't instantiate at all with std::string (it seems that the compiler instantiates with std::string as soon as it sees the specialization and that it, before it actually processes the specialization, complains about the ambiguous overload which the specialization, in turn, will "disambiguate").
Compiler output:
p.cpp: In instantiation of 'struct A<std::basic_string<char> >':
p.cpp:10:27: required from here
p.cpp:6:14: error: 'std::string A<T>::foo(T) [with T = std::basic_string<char>; std::string = std::basic_string<char>]' cannot be overloaded
std::string foo(T e) { return "ptemplate: foo_T"; }
^
p.cpp:5:14: error: with 'std::string A<T>::foo(std::string) [with T = std::basic_string<char>; std::string = std::basic_string<char>]'
std::string foo(std::string s) { return "ptemplate: foo_string"; }
^
I would like it to just skip through the implementation of foo() in the primary template and use the specialization without considering the primary template foo(). Could it be done somehow, maybe with non-type template parameters, or do I have to make a fully specialized class template for std::string with all the code duplication it implies (I prefer not to use inheritance here)... Other suggestions?
When you specilize your member function you still get the double ambiguous declaration. Waht you need is to specialize the struct template:
template<>
struct A<std::string> {
std::string foo(std::string s) { return "ptemplate: foo_string"; }
};
If there are many members to the A struct maybe you can refactor:
template<typename T>
struct Afoo
{
std::string foo(T s) { ... }
std::string foo(std::string s) { ... }
};
template<>
struct Afoo<std::string>
{
std::string foo(std::string s) { ... }
};
template<typename T>
struct A : Afoo<T>
{
//a lot of code
};
I'm going to answer this myself since I've been diving deep into this subject today and I think these solutions are nice. All other posts up to this point have been contributive and have had attractive details with potential in other situations. However, I preferred to do it with these things in mind:
Avoid the use of more than one class template
Avoid too complicated specializations as far as possible
Avoid using inheritance and refactor into base and derived classes
Avoid the use of extra wrappers
Please feel free to comment before I accept it as my answer.
Another good and inspiring post on the subject focusing on the use of member function overloading rather than specializations can be found at explicit specialization of template class member function
Solution 1
template<class T>
struct A {
template<class V = T> std::string foo(T) { return "foo_T"; }
std::string foo(std::string) { return "foo_std::string"; }
std::string foo(const char *) { return "foo_const char *"; }
};
template<> template<>
std::string A<std::string>::foo(std::string s) { return foo(s); }
I think this is a dense and understandable solution allowing all class instantiations to use foo(std::string) and foo(const char *) (for passing a string as an rvalue). The use of a dummy template parameter effectively stops class instantiations with std::string from resulting in ambiguous overloads at the same time as the actual template argument hinders uncontrolled function instantiations with unpredictable function arguments. The only problem might come from a class instantiation with std::string that might use the template instead of the regular member function if explicitly called with foo<std::string>(std::string) in which way I would want the class to use the regular foo(std::string) instead of the function template for other instantiations. This is resolved by using a single template specialization.
Solution 2
template<class T>
struct A {
template<class V> std::string foo(V s) { return foo_private(s); }
private:
template<class V = T> std::string foo_private(T) { return "foo_T"; }
std::string foo_private(const char *) { return "foo_const char *"; }
std::string foo_private(std::string) { return "foo_std::string"; }
};
This version allows us to skip the specialization to the benefit of a second template in the class declaration.
Both versions used with:
int main() {
A<int> a;
std::cout << a.foo(10) << std::endl;
std::cout << a.foo("10") << std::endl;
A<std::string> b;
std::cout << b.foo<std::string>("10") << std::endl;
std::cout << b.foo("10") << std::endl;
return 0;
}
... outputted:
foo_T
foo_const char *
foo_const char *
foo_std::string
The error is saying that you ended up creating two method with the same signature.
That is because the struct has been templated with a std::string as parameter.
You should made the function as a templated function, using its own template parameters 'K' not related to the structure template parameter 'T'. Then you can achieve template specialization for the function only.
I admit that the solution I offer below, is a hacky solution indeed, but it does accomplish what you're trying to do and it's kinda funny. Please consider it thoroughly before you use this ;-)
I work around the issue by creating a new type, called FakeType, which can be constructed from your template-type T. The second overload of foo is now for FakeType<T> instead of T, so even when T == string there will be two different overloads:
template <typename T>
struct FakeType
{
T t;
FakeType(T const &t_): t(t_) {}
operator T() { return t; }
};
template <typename T>
struct A
{
string foo(string s) { return "ptemplate: foo_string"; }
string foo(FakeType<T> e) { return "ptemplate: foo_T"; }
};
For the case that T != string:
A<int>().foo("string"); // will call foo(string s)
A<int>().foo(1); // will call foo(FakeType<int> e)
In the latter case, the int will be promoted to a FakeType<int>, which can be used as a regular int through the conversion operator.
For the case that T == string:
A<string>().foo("string"); // will still call foo(string s)
Because the compiler will always prefer an overload for which no promotion is necessary.
PS. This approach assumes that foo is going to get its arguments either by value, or by const-reference. It will break as soon as you try to pass by reference (this can be fixed).

non-type template parameter of user-defined type

I'm trying to define a template-class that has a non-type template parameter of a user-defined type. Unfortunately, without success so far. The real code is a bit too lengthy, but a simplified example looks like this:
#include <iostream>
template <class T>
class Maybe {
bool is_ = false;
T value_;
public:
constexpr Maybe() = default;
constexpr Maybe(T value) : is_(true), value_(value) {}
constexpr bool is() const { return is_; }
};
template <Maybe<int> parm>
struct Test {
void say() const {
std::cout << "parm is " << (parm.is() ? "set" : "not set") << ".\n";
}
};
int main() {
Test<Maybe<int>{}> not_set;
Test<Maybe<int>(2)> is_set;
not_set.say();
is_set.say();
}
When I try to compile this code (with Clang 3.4) I get the following error message:
test.cc:15:22: error: a non-type template parameter cannot have type
'Maybe<int>'
template <Maybe<int> parm>
^
test.cc:23:10: error: value of type 'Maybe<int>' is not implicitly
convertible to 'int'
Test<Maybe<int>{}> not_set;
^~~~~~~~~~~~
test.cc:24:10: error: value of type 'Maybe<int>' is not implicitly
convertible to 'int'
Test<Maybe<int>(2)> is_set;
^~~~~~~~~~~~~
3 errors generated.
Now, I know that a non-type template parameter has to fulfill some conditions. However, I thought that being constexpr would be sufficient. Or can it really only be one of the built-in integral types?
Is there a way to pass non-type template parameters of my own user-defined type?
No, you cant.
n3376 14.1/7
A non-type template-parameter shall not be declared to have floating
point, class, or void type.
template<double d> class X; // error
template<double* pd> class Y; // OK
template<double& rd> class Z; // OK
so, you can pass pointer, or reference, but not object of class-type.
live example
this whole problem is the very reason why rational numbers are implemented as template-class with the actual numbers in the template parameters. to get a template-parameter storing more than just an int, you must create a similar class as std::ratio which also is evaluated at compile-time only.
as for your actual example, consider writing something similar to:
template<class T, T ... Params>
class Maybe {
and then
Test<Maybe<int,5> > is_set;
or
Test<Maybe<int> > not_set;
I know that this question is old, but I would like to point out a template meta programming approach to this.
In c++ you can pass any type to a template like that, so why not just make it a type?
In order to do that, you will want to make a wrapper class for your Maybe class:
template <typename T>
struct maybe_wrap
{
Maybe<T> value{};
}
template<typename T, T value>
struct maybe_wrap
{
Maybe<T> value{value};
}
Then just pass the maybe_wrap as a typename and just access the maybe_wrap<int, 3>().value of it when you need it!
The only restriction of this is that T might not be one of the non-type values (int, bool, etc).
In that case, just use the above logic again!
In C++20, this is possible using structural literal class types:
#include <iostream>
struct NullOptT {} NullOpt;
/**
* Literal class type.
*
* Represents an optionally provided `int`.
*/
struct OptionalInt {
constexpr OptionalInt(NullOptT) {}
constexpr OptionalInt(int value): has_value(true), value(value) {}
const bool has_value = false;
const uint32_t value {};
};
/**
* Prints whether or not a value was provided for "maybe" WITHOUT branching :)
*/
template<OptionalInt maybe>
void Print() {
if constexpr(maybe.has_value) {
std::cout << "Value is: " << maybe.value << std::endl;
} else {
std::cout << "No value." << std::endl;
}
}
// Note: implicit conversions are at play!
int main()
{
Print<123>(); // Prints "Value is: 123"
Print<NullOpt>(); // Prints "No value."
}
I wrote up a blog post with more detail on the usage and restrictions of class literal NTTPs here: Literal Classes as Non-type Template Parameters in C++20.

Type checking template class parameters

I am trying to achieve type checking of template class parameters by disallowing implicit type conversions such as string->bool thereby throwing compile error.
The specific scenario is a simple one as follows:
#include <iostream>
#include <string>
using namespace std;
template <class T>
class myPair {
T a, b;
public:
myPair(T first, T second ) {
a = first;
b = second;
}
void test();
};
typedef myPair<bool> boolParm;
template<class T>
void myPair<T>::test() {
if(a == true) {
cout << "a is true" << endl;
} else {
cout << "a is false" << endl;
}
if(b == true) {
cout << "b is true" << endl;
} else {
cout << "b is false" << endl;
}
}
int main() {
boolParm myObj(false, "false");
myObj.test();
return 0;
}
The output of the above scenario is undesirable since the user may inadvertently pass 2 different types: bool and string and receive the first one as false (correct since passed as bool) but the second one will be true (incorrect since implicit type conversion from string to bool).
I wish to restrict the user code in main() to throw compile errors and disallowing string/int parameters to pass in the constructor. It should only allow bool.
I tried by using an overloaded constructor myPair(bool first, string second) but it didn't match since I guess the implicit type conversion from string->bool happens before the constructor is called.
Is there any solution using template specializations in this scenario?
Any help is highly appreciated
Thanks
One workaround is to add a templated factory function to create the myPair.
template <typename T>
myPair<T> makeParam(T a, T b) {
return myPair<T>(a, b);
}
That will fail to compile with ambiguous template parameter T if the types don't match. You can extend this with template specializations explicitly forbidding certain types for T. Your main function will then look something like:
int main() {
boolParm myObj = makeParam(false, "false");
myObj.test();
return 0;
}
Alternatively change the constructor:
template <typename U, typename V>
myPair(U a, V b);
And specialize as necessary
An example of such specialization:
template <class T>
class myPair {
T a, b;
public:
template <typename U, typename V> // generic version
myPair(U first, V second)
{
// intentionally fail to compile
static_assert(false, "don't support generic types");
}
template <> // template specialization
myPair(T first, T second)
{
// explicitly require exactly type T
a = first;
b = second;
}
};
It is indeed weird behavior at first glance; but as far as I can say, you can't prohibit that - not for primitive types like bool, anyway.
The implicit conversion of parameters happen before you get a say on it, and it seems there is an implicit primitive type conversion from char const * to bool.
See also e.g. this other question: Why does a quoted string match bool method signature before a std::string?