def _create_instance(self, cls, args, ref=None):
        """
        Returns an instance of `cls` with `args` passed as arguments.

        Recursively inspects `args` to create nested objects and functions as
        necessary.

        `cls` will only be considered only if it's an object we track
         (i.e.: troposphere objects).

        If `cls` has a `props` attribute, nested properties will be
         instanciated as troposphere Property objects as necessary.

        If `cls` is a list and contains a single troposphere type, the
         returned value will be a list of instances of that type.
        """
        if isinstance(cls, Sequence):
            if len(cls) == 1:
                # a list of 1 type means we must provide a list of such objects
                if (isinstance(args, basestring) or
                        not isinstance(args, Sequence)):
                    args = [args]
                return [self._create_instance(cls[0], v) for v in args]

        if isinstance(cls, Sequence)\
           or cls not in self.inspect_members.union(self._custom_members):
            # this object doesn't map to any known object. could be a string
            # or int, or a Ref... or a list of types such as
            # [basestring, FindInMap, Ref] or maybe a
            # validator such as `integer` or `port_range`
            return self._convert_definition(args)

        elif issubclass(cls, AWSHelperFn):
            # special handling for functions, we want to handle it before
            # entering the other conditions.
            try:
                if issubclass(cls, Tags):
                    arg_dict = {}
                    for d in args:
                        arg_dict[d['Key']] = d['Value']
                    return cls(arg_dict)

                if (isinstance(args, Sequence) and
                        not isinstance(args, basestring)):
                    return cls(*self._convert_definition(args))

                if issubclass(cls, autoscaling.Metadata):
                    return self._generate_autoscaling_metadata(cls, args)

                if issubclass(cls, Export):
                    return cls(args['Name'])

                args = self._convert_definition(args)
                if isinstance(args, Ref) and issubclass(cls, Ref):
                    # watch out for double-refs...
                    # this can happen if an object's .props has 'Ref'
                    # as the expected type (which is wrong and should be
                    # changed to basestring!)
                    return args

                return cls(args)

            except TypeError as ex:
                if '__init__() takes exactly' not in ex.message:
                    raise
                # special AWSHelperFn typically take lowercased parameters,
                # but templates use uppercase. for this reason we cannot
                # map to most of them, so we fallback with a generic one.
                # this might not work for all types if they do extra
                # processing in their init routine
                return GenericHelperFn(args)

        elif isinstance(args, Mapping):
            # we try to build as many troposphere objects as we can by
            # inspecting its type validation metadata
            kwargs = {}
            kwargs.update(args)
            for prop_name in getattr(cls, 'props', []):
                if prop_name not in kwargs:
                    continue  # the user did not specify this value; skip it
                expected_type = cls.props[prop_name][0]

                if (isinstance(expected_type, Sequence) or
                        expected_type in self.inspect_members):
                    kwargs[prop_name] = self._create_instance(
                        expected_type, kwargs[prop_name], prop_name)
                else:
                    kwargs[prop_name] = self._convert_definition(
                        kwargs[prop_name], prop_name)

            args = self._convert_definition(kwargs)
            if isinstance(args, Ref):
                # use the returned ref instead of creating a new object
                return args
            if isinstance(args, AWSHelperFn):
                return self._convert_definition(kwargs)
            assert isinstance(args, Mapping)
            return cls(title=ref, **args)

        return cls(self._convert_definition(args))