1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
/**
* @file llmake.h
* @author Nat Goodspeed
* @date 2015-12-18
* @brief Generic llmake<Template>(arg) function to instantiate
* Template<decltype(arg)>(arg).
*
* Many of our class templates have an accompanying helper function to
* make an instance with arguments of arbitrary type. llmake()
* eliminates the need to declare a new helper function for every such
* class template.
*
* also relevant:
*
* Template argument deduction for class templates (C++17)
* https://en.cppreference.com/w/cpp/language/class_template_argument_deduction
*
* $LicenseInfo:firstyear=2015&license=viewerlgpl$
* Copyright (c) 2015, Linden Research, Inc.
* $/LicenseInfo$
*/
#if ! defined(LL_LLMAKE_H)
#define LL_LLMAKE_H
// If we're using a compiler newer than VS 2013, use variadic llmake().
#if (! defined(_MSC_VER)) || (_MSC_VER > 1800)
/**
* Usage: llmake<SomeTemplate>(args...)
*
* Deduces the types T... of 'args' and returns an instance of
* SomeTemplate<T...>(args...).
*/
template <template<typename...> class CLASS_TEMPLATE, typename... ARGS>
CLASS_TEMPLATE<ARGS...> llmake(ARGS && ... args)
{
return CLASS_TEMPLATE<ARGS...>(std::forward<ARGS>(args)...);
}
#else // older implementation for VS 2013
template <template<typename> class CLASS_TEMPLATE, typename ARG1>
CLASS_TEMPLATE<ARG1> llmake(const ARG1& arg1)
{
return CLASS_TEMPLATE<ARG1>(arg1);
}
template <template<typename, typename> class CLASS_TEMPLATE, typename ARG1, typename ARG2>
CLASS_TEMPLATE<ARG1, ARG2> llmake(const ARG1& arg1, const ARG2& arg2)
{
return CLASS_TEMPLATE<ARG1, ARG2>(arg1, arg2);
}
#endif // VS 2013 workaround
/// dumb pointer template just in case that's what's wanted
template <typename T>
using dumb_pointer = T*;
/**
* Same as llmake(), but returns a pointer to a new heap instance of
* SomeTemplate<T...>(args...) using the pointer of your choice.
*
* @code
* auto* dumb = llmake_heap<SomeTemplate>(args...);
* auto shared = llmake_heap<SomeTemplate, std::shared_ptr>(args...);
* auto unique = llmake_heap<SomeTemplate, std::unique_ptr>(args...);
* @endcode
*/
// POINTER_TEMPLATE is characterized as template<typename...> rather than as
// template<typename T> because (e.g.) std::unique_ptr has multiple template
// arguments. Even though we only engage one, std::unique_ptr doesn't match a
// template template parameter that itself takes only one template parameter.
template <template<typename...> class CLASS_TEMPLATE,
template<typename...> class POINTER_TEMPLATE=dumb_pointer,
typename... ARGS>
POINTER_TEMPLATE<CLASS_TEMPLATE<ARGS...>> llmake_heap(ARGS&&... args)
{
return POINTER_TEMPLATE<CLASS_TEMPLATE<ARGS...>>(
new CLASS_TEMPLATE<ARGS...>(std::forward<ARGS>(args)...));
}
#endif /* ! defined(LL_LLMAKE_H) */
|