Prevent ADL by template parameters
I currently have a class template that accepts a number of types. Each type might need to be created with a class. I currently have something like this:
template <typename... Types>
struct TypeList; // Not defined
struct Placeholder; // Not defined
template <typename Types, typename AnotherType = Default>
class MyClass
{
// ...
};
Then you can use it like this:
typedef MyClass<TypeList<Container1<Placeholder>, Container2<std::string,
Placeholder>, OtherType>, OptionalType> MyTypedef;
MyTypedef my_object;
MyClass
replace the look and feel Placeholder
with itself, use the result types and you should be fine.
The problem comes up when I try to do something like any of these:
MyTypedef *my_ptr = &my_object;
my_free_function(my_object);
Both of them throw a compiler error because the compiler is trying to instantiate Container1<Placeholder>
and Container2<std::string, Placeholder>
search for dependent arguments (ADL), and that instance itself Placeholder
fails.
I know ADL can be avoided, for example
MyTypedef *my_ptr = std::addressof(my_object);
(my_free_function)(my_object);
However, I don't want to burden the user with the MyClass
need to suppress ADL all the time. Is there another easy way to provide the user with a list of types not used for ADL?
source to share
Okay, everything works for me. The trick was to use the dependent type directly, rather than use a template. My final solution was to define the TypeList like this:
template <typename... Types>
struct TypeList
{
private:
struct Holder
{
private:
typedef TypeList<Types...> InnerTypeList;
template <typename Types, typename AnotherType>
friend class MyClass;
};
public:
typedef Holder type;
};
Then MyClass users can do
typedef MyClass<TypeList<Container1<Placeholder>, Container2<std::string,
Placeholder>::type, OtherType>, OptionalType> MyTypedef;
MyTypedef my_object;
Notice the addition of ':: type'
Finally, in MyClass, I replaced
typedef typename SubstituteType<Types, Placeholder, MyClass>::type InternalTypeList;
from
typedef typename SubstituteType<Types::InnerTypeList, Placeholder, MyClass>::type
InternalTypeList;
gives me the same type for InternalTypeList
as before.
Since the dependent type Holder
has no template parameters of its own, the compiler does not need to create Placeholder instances for ADL targets, and everything works as expected.
source to share